React.memo组件内useCallback是否必要?多场景技术问询
先看示例代码:
import React, { useCallback } from 'react'; type UserInputProps = { onChange: (value: string) => void; }; const UserInput = React.memo(({ onChange }: UserInputProps) => { // 此处的`useCallback`是否多余? const handleChange = useCallback( (event) => { onChange(event.target.value); }, [onChange] ); return <input type="text" onChange={handleChange} />; }); export default UserInput;
技术疑问
- 当组件仅接收
onChange这一个props时,由于组件已通过React.memo基于onChange实现记忆化,此时内部的useCallback是否属于冗余操作? - 若为组件新增一个props(如input的初始值
value),此时useCallback是否会起到作用?因为若不使用它,当onChange未变化但value发生变化时,handleChange会被重新创建,该判断是否正确?
疑问1解答
没错,这时候useCallback确实是冗余的。
原因很直接:React.memo已经在props层面做了记忆化——只有当onChange的引用发生变化时,UserInput组件才会重新渲染。如果去掉useCallback,只有在组件重新渲染(也就是onChange变化时),handleChange才会被重新创建一次,这种函数创建的开销微乎其微,完全不影响性能。
反过来想,就算保留useCallback,它的依赖也是onChange:当onChange变化时,useCallback还是会返回新的函数引用,和直接创建没区别;当onChange不变时,组件根本不会重新渲染,useCallback连执行的机会都没有。所以此时useCallback属于多余代码,去掉反而让逻辑更简洁。
疑问2解答
你的判断是完全正确的,这时候useCallback就会发挥实际作用了。
当组件新增value这个props后,情况就不同了:只要value发生变化,哪怕onChange的引用没变,React.memo会因为检测到props变化(浅比较value)而触发组件重新渲染。
如果没有useCallback,每次组件重新渲染时,handleChange都会被创建成新的函数引用,再传递给<input>。虽然原生input接收新函数不会有明显性能问题,但如果这个子组件是自定义的、且同样用了React.memo,那每次传递新函数都会导致子组件不必要的重新渲染。
而用了useCallback之后,只要依赖数组里的onChange不变,handleChange就会始终返回同一个引用。哪怕组件因为value变化重新渲染,传递给<input>的onChange还是同一个值,避免了不必要的子组件更新,也符合React性能优化的最佳实践。
内容的提问来源于stack exchange,提问作者Zizheng Tai

