这是一个自定义钩子,它接受一个更新函数,并返回一个只有当更新函数返回 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 钩子是最后的手段。