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 时才会改变的值,可以在第二个参数中传递给 useEffect
或 useCallback
或 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;
例如,这将仅在 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?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 redux-sagas 与 react-hooks 一起使用