反应钩子-我如何实现应该组件更新?

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

例如:

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

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

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

92848 次浏览

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

这里有一个自定义钩子,它接受一个 updater 函数,并返回一个仅在 updater 函数返回 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)
}, [])

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

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

在上面的 Gabriele Petrioli评论中,有一个指向 React.note 文档的链接,该文档解释了如何实现 should dComponent entUpdate。我当时正在谷歌“应该组件更新 + 使用效果 + 反应钩子”的组合,结果出现了这个。因此,在解决了与链接文档相关的问题之后,我想我也应该把这些信息带到这里。

这是实现 should-Component 更新的老方法:

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

The New React Hooks way:

React.memo(function MyComponent (props) {


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


})

我知道你可能在你的问题中要求更多,但对于任何人来自谷歌寻找如何实现应该组件更新使用反应钩子,你去。

文件在这里: 如何实现组件更新

另一种方法是使用 useRef 来保存数据,并使用 useStateONLY 来存储要显示的数据。 有时候,这种方法比备忘录方法更有效: 我最近遇到过一个案例,当使用 React.note 时,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>);

PAT-O-MATION 的回答是,
Memorial 还接受第二个参数,这是一个函数,可以用来确定组件是否 应该呈现与否。

如果函数返回 true,那么组件将不会在道具更改时重新呈现,相反,它会在返回值为 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值发生变化,它也不会重新呈现

除了 阿维纳什的的答案。 返回值的重要注意事项:

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