React Hooks-如何实现shouldComponentUpdate?

时间:2019-02-06 10:56:00

标签: reactjs react-hooks

我知道您可以通过将数组作为可选的第二个参数传递来告诉React跳过效果。

例如:

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes

但是,如果我想控制比较怎么办?添加我自己的比较逻辑。

我希望像React.memo这样的东西可以将函数作为第二个参数传递。

6 个答案:

答案 0 :(得分:16)

添加到PAT-O-MATION的答案中,
React.memo还接受第二个参数,该参数可用于确定组件是否 应该呈现还是不呈现。

如果函数返回true,则组件将不会在更改该prop时重新渲染,相反,当返回值为false时,组件将更新

function SomeComp({prop1, prop2}) {
    return(
        ..
    )

}
React.memo(SomeComp, (props, nextProps)=> {
    if(props.prop1 === nextProps.prop1) {
        // don't re-render/update
        return true
    }
})

注意:只有在回调函数返回false时,组件才会重新呈现,因此在上述情况下,即使prop2值更改,它也不会重新呈现

答案 1 :(得分:3)

Gabriele Petrioli 上方的评论中,链接到React.memo文档,该文档解释了如何实现shouldComponentUpdate。我正在搜索shouldComponentUpdate + useEffect +“ react hooks”的组合,结果出现了。因此,在解决了链接文档中的问题之后,我想我也将信息带到这里。

这是实现shouldComponentUpdate的旧方法:

class MyComponent extends React.Component{
  shouldComponentUpdate(nextProps, nextState){
    return nextProps.value !== this.props.value;
  }
  render(){
    return (
     <div>{"My Component " + this.props.value}</div>
    );  
 }
}

新的React Hooks方式:

React.memo(function MyComponent (props) {

  return <div>{ "My Component " + props.value }</div>

}) 

我知道您可能在问题中提出了更多的要求,但是对于任何来自google的人来说,他们都知道如何实现shouldComponentUpdate。

文档在这里: how-do-i-implement-shouldcomponentupdate

答案 2 :(得分:2)

另一种选择是使用useRef来保存数据,而仅使用useState来存储要显示的数据。 有时这比备忘录方法更好:最近我遇到一个案例,其中React在使用React.memo时仍然不必要地渲染,并且弄乱了一些PIXI的显示。 下面的方法为我解决了这个问题...希望我没有做反模式:-)

const countRef = useRef(0);
const [countDisplay, setCountDisplay] = useState(0);

yourUpdateFunction = () => {
  // This is where count gets updated
  countRef.current = countRef.current + 1;
  if ((countRef.current % 2) === 0) setCountDisplay(countRef.current);
}

return (<p>countDisplay</p>);

答案 3 :(得分:0)

如果在数组中传递的属性发生更改,则传递可选的第二个数组参数会启动effect函数-就像在将prop传递给组件时,类组件中的shouldComponentUpdate方法将运行。您可以根据参数的值决定效果功能-是否要应用效果。

答案 4 :(得分:0)

这是一个自定义钩子,它接受一个updater函数,并返回一个仅在updater函数返回true时才更改的值,该值可以在第二个参数中传递给useEffectuseCallback或{ {1}}强制重新渲染:

useMemo

例如,这只会在计数为偶数时更新文档标题:

function useShouldRecalculate(shouldRecalculateFn) {
  const prevValueRef = useRef(0);
  if(shouldRecalculateFn()) {
    // If we need to recalculate, change the value we return
    prevValueRef.current += 1;
  } // else we return the same value as the previous render, which won't trigger a recalculation
  return prevValueRef.current;
}

为什么您可能不应该这样做

在大多数情况下,我不建议您这样做。

通常,将使用惯用的钩子API来完成同一任务的方法更加简洁。 (以上示例可能只是在更新文档标题的行周围放置了const shouldUpdateTitle = useShouldRecalculate( () => count % 2 === 0 ); useEffect(() => { document.title = `You clicked ${count} times`; }, [shouldUpdateTitle]); // eslint-disable-line react-hooks/exhaustive-deps 块。)

也许更重要的是,if参数不仅涉及优化,而且还涉及保持闭包值是最新的,并避免出现诸如以下的错误:

deps

const [count, setCount] = useState(0) const increment = useCallback(() => { // Bug: `count` is always 0 here, due to incorrect use of the `deps` argument setCount(count + 1) }, []) linter规则将捕获此错误,但是您必须在使用自定义逻辑来控制执行的任何位置禁用该规则。

使用自定义的备忘逻辑可能会使您的组件更容易出现错误,并且通常很难进行推理。因此,我认为这react-hooks/exhaustive-deps钩了不得已的办法。

答案 5 :(得分:0)

除了 Avinash的答案。 返回值的重要说明:

shouldComponentUpdate() {
  // returns true by default
  // return false if you don't need re-render
}

export default React.memo(Component, (props, nextProps) => {
  if(props.prop1 === nextProps.prop1) {
    // return true if you don't need re-render
  }
})