为什么 `useCallback` 不能始终返回相同的引用?
为什么 `useCallback` 不能始终返回相同的引用?
我不明白为什么每次更新依赖项时,useCallback
总是会返回一个新的引用。这导致了很多次重新渲染,而 React.memo()
可以避免这种情况。\n对于这个 useCallback
的实现,是否存在任何问题?\n
export function useCallback(callback) { const callbackRef = useRef(); callbackRef.current = callback; return useState(() => (...args) => callbackRef.current(...args) )[0]; }
\n与内置实现相比,使用这个实现确实对性能有显著的积极影响。\n
个人结论:
\n只要你意识到了其中的影响,即如 @Bergy 所指出的,无法存储一个回调以供稍后使用(例如在 setTimeout
之后),并期望回调具有与同步调用相同的效果,那么使用引用来实现没有任何不好的地方。
\n但在我看来,这是首选的行为,因此没有缺点。\n
更新:
\nReact 正在引入一个内置的 hook,可以做到这一点。它将被称为 useEvent。
问题的出现原因是因为useCallback不能始终返回相同的引用,这是由其工作原理决定的。useCallback根据依赖项的变化返回一个记忆化的回调函数,只有当依赖项发生变化时,它才会重新渲染组件。但是useMemo只能保存可变的值。
要解决这个问题,可以使用useMemo来保存回调函数的引用,而不是使用useCallback。由于useMemo可以保存可变的值,因此可以确保每次渲染时返回相同的引用。下面是一个示例:
const [count, setCount] = useState(0); const handleClick = useMemo(() => { return () => { setCount(count + 1); console.log(count + 1); }; }, [count]);
通过使用useMemo,我们将回调函数作为一个函数表达式返回,并将其传递给useMemo的依赖项数组。这样,每当count发生变化时,useMemo都会重新计算回调函数,并返回一个新的函数引用。这确保了每次渲染都返回相同的引用,从而避免了useCallback不能始终返回相同引用的问题。
总结一下,尽管useCallback和useMemo的用例不同,但我们可以使用useMemo来解决useCallback不能始终返回相同引用的问题。通过使用useMemo保存回调函数的引用,我们可以确保每次渲染时返回相同的引用,从而避免不必要的重新渲染。
为什么`useCallback`不能始终返回相同的引用?
问题的出现原因:
在上述代码示例中,使用自定义的`useCallback`实现,会导致存储在`printerHistory`中的函数引用始终指向最新的`useCallback`参数,而不是独立的闭包。这会导致在每次调用时,所有函数都只打印当前的`value`值,而不是对应的历史值。这可能会影响到存储引用以供稍后使用的情况。
解决方法:
为了解决这个问题,可以使用原生的`useCallback`来确保每个函数都是独立的闭包。这样可以保证存储在`printerHistory`中的函数引用都是不同的,并且在每次调用时都会打印对应的历史值。
这个问题的出现说明了自定义的`useCallback`实现与原生的`useCallback`在处理函数引用时存在差异。在某些情况下,使用自定义实现可能会导致意外的结果。因此,为了确保代码的可靠性和一致性,建议使用原生的`useCallback`来处理函数引用。
补充说明:
在实际开发中,可能会遇到更复杂的场景,例如需要选择历史记录条目并在回调函数中进行复杂的计算。在这种情况下,使用原生的`useCallback`可以更好地满足需求,因为它可以确保每个函数都是独立的闭包,并且可以根据需要执行复杂的计算或副作用。
通过对比自定义的`useCallback`实现和原生的`useCallback`,我们可以看到自定义实现可能导致函数引用的不一致性,而原生实现可以保证每个函数都是独立的闭包。因此,在使用`useCallback`时,建议使用原生的实现来确保代码的可靠性和一致性。