我不明白为什么useCallback
每次更新deps时都会返回一个新的ref,这会导致React.memo()
本可以避免的很多重渲染。useCallback
的这个实现有什么问题(如果有的话)?
export function useCallback(callback) {
const callbackRef = useRef();
callbackRef.current = callback;
return useState(() =>
(...args) => callbackRef.current(...args)
)[0];
}
使用这个方法而不是内置的实现肯定会对性能产生显著的积极影响。
自己的结论:
- 没有理由不使用一个使用ref的实现来代替内建的**in,只要你意识到它的含义,也就是说,正如@Bergy所指出的,你不能存储一个回调以供以后使用(例如在
setTimeout
之后),并期望回调具有与你同步调用它相同的效果。
- 没有理由不使用一个使用ref的实现来代替内建的**in,只要你意识到它的含义,也就是说,正如@Bergy所指出的,你不能存储一个回调以供以后使用(例如在
不过在我看来,这是首选的行为,所以没有缺点。🥂.
更新:
有一个React RFC引入了一个内置的钩子,它可以被称为useEvent
2条答案
按热度按时间hwamh0ep1#
useCallback
的这个实现有什么问题(如果有的话)?我怀疑当有人存储对回调的引用以备将来使用时会产生意想不到的后果,因为它会改变回调正在做的事情:
(Sure,在这个简化的演示中,
printer
回调只不过是value
本身上的一个无用闭包,但是您可以想象一个更复杂的情况,其中您可以选择单个历史记录条目,并希望在回调中使用复杂的按需计算)对于原生
useCallback
,存储在printerHistory
中的函数将是不同值上的不同闭包,而对于您的实现,它们都将是同一个函数,引用最新的useCallback
参数,并且在每次调用时只打印当前值。更详细的描述请参见
useEvent
提案,其中肯定有一些用例,比如solvingstaleclosure问题,但这与useCallback
解决的问题不同。2exbekwf2#
useCallback和useMemo的用例是不同的,您说过useCallback返回回调的记忆版本,只有当其中一个依赖项发生变化时才会发生变化,因此它会根据依赖项的变化重新呈现组件,但useMemo只保存可变值,通常我们使用useCallback来处理事件处理程序,例如,假设当您单击按钮时,显示按钮的点击次数,这里使用useCallback实现click事件。
要获得新的增加的计数值并在每次单击按钮时显示它的值,需要重新呈现。再说一遍,useCallback和useMemo的用例取决于用途。