React Hooks - 我如何实现 shouldComponentUpdate?

Posted

技术标签:

【中文标题】React Hooks - 我如何实现 shouldComponentUpdate?【英文标题】:React Hooks - How do I implement 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 这样您可以将函数作为第二个参数传递。

【问题讨论】:

你需要什么样的比较逻辑。当值发生变化时,效果应该运行。任何其他类型的比较都可以作为 useEffect 中的 if-else 块 查看钩子文档中的How do I implement shouldComponentUpdate?。 你在找React.memo 【参考方案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 参数只允许您控制效果执行,而不是重新渲染。

以上是关于React Hooks - 我如何实现 shouldComponentUpdate?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 React Hooks 实现复杂组件的状态管理

如何将 redux-sagas 与 react-hooks 一起使用

react-hooks实现下拉刷新

React Native 中带有 React Hooks 的基本全局状态

在 React 中使用 Hooks 实现倒数计时器

函数式编程看React Hooks简单React Hooks实现