【问题标题】:React Hooks - How do I implement shouldComponentUpdate?React Hooks - 我如何实现 shouldComponentUpdate?
【发布时间】:2019-06-30 07:22:28
【问题描述】:

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

例如:

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

但是如果我想控制比较呢?添加我自己的比较逻辑。

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

【问题讨论】:

标签: reactjs react-hooks


【解决方案1】:

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

这是实现 shouldComponentUpdate 的旧方式:

class MyComponent extends React.Component{
  shouldComponentUpdate(nextProps){
    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 并正在寻找如何使用 React Hooks 实现 shouldComponentUpdate 的任何人,您就可以了。

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

【讨论】:

  • 就是这样!谢谢
【解决方案2】:

添加到 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 值发生变化,它也不会重新渲染

【讨论】:

  • 错别字... SomeComp 声明中 prop1 前的花括号
  • 注意:在 React.memo 的情况下返回 true 意味着不重新渲染,这与 shouldComponentUpdate 相反,其中 true 意味着组件应该重新渲染。
  • 你可以简单地写成:return props.prop1 === nextProps.prop1
【解决方案3】:

除了 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
  }
})

【讨论】:

    【解决方案4】:

    这是一个自定义钩子,它接受一个更新函数,并返回一个只有当更新函数返回 true 时才会改变的值,可以在第二个参数中传递给 useEffectuseCallbackuseMemo 以强制重新渲染:

    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;
    }
    

    例如,这将仅在 count 为偶数时更新文档标题:

    const shouldUpdateTitle = useShouldRecalculate(
      () => count % 2 === 0
    );
    
    useEffect(() => {
      document.title = `You clicked ${count} times`;
    }, [shouldUpdateTitle]); // eslint-disable-line react-hooks/exhaustive-deps
    

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

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

    一般来说,使用惯用的钩子 API 会有更简洁的方法来完成相同的任务。 (上面的示例可能只是在更新文档标题的行周围放置了一个 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)
    }, [])
    

    react-hooks/exhaustive-deps linter 规则将捕获此错误,但您必须在使用自定义逻辑控制执行的任何地方禁用该规则。

    使用自定义记忆逻辑可能会使您的组件更容易出错,并且通常更难以推理。所以我认为这个 useShouldRecalculate 钩子是最后的手段。

    【讨论】:

      【解决方案5】:

      另一种方法可能是使用 useRef 来保存您的数据,并仅使用 useState 来存储您要显示的数据。 有时这比备忘录方法效果更好:我最近遇到过一个案例,当使用 React.memo 时,React 仍然在进行不必要的渲染,并且它弄乱了一些 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>);
      

      【讨论】:

        【解决方案6】:

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

        【讨论】:

        • 这不是 OP 所要求的。第二个 useEffect 参数只允许您控制效果执行,而不是重新渲染。
        猜你喜欢
        • 2021-12-09
        • 2019-09-11
        • 2017-01-18
        • 2019-07-28
        • 1970-01-01
        • 1970-01-01
        • 2020-04-11
        • 2020-01-20
        相关资源
        最近更新 更多