useCallback 接收一个内联回调函数和一个依赖项数组,依赖项改变时才会更新。
使用 useCallback 出现的问题
- useCallback 依赖不传 导致代码大片飘红
- useCallback 会在依赖不变时缓存该函数,在组件重新render 时 不需要重新的创建。但同时也占用了内存 ,使其不能释放
- 在组件内部抛出的回调如果用useCallback 包裹 会出现闭包的问题 难以定位
哪些场景不建议使用useCallback ?
-
正常组件的回调函数
正常组件的回调函数并不能其到优化作用
// 错误⽰例
function App() {
const onChange = useCallback(() => { ... }, [xxx]);
return (
<input onChange={onChange} />
);
}
// 正确⽰例
function App() {
const onChange =() => { ... };
return (
<input onChange={onChange} />
);
}
- 自定义组件内的回调(无React.memo或PureComponent 优化时)
如果父组件重新渲染,子组件也必定会重新渲染,如果想要子组件在props未发生变化时不重新进行渲染需要给子组件用memo 进行包裹
eg: 以下自定义组件如果并未用memo 包裹 且嵌套多层 那在父组件渲染时 useCallback 并未起到优化作用,input 组件还是会重新渲染
function Input(props) {
return <input onChange={props.onChange} />;
}
// 错误⽰例
function App() {
const onChange = useCallback(() => { ... }, [xxx]);
return (
<Input onChange={onChange} />
);
}
// 正确⽰例
function App() {
const onChange =() => { ... };
return (
<Input onChange={onChange} />
);
}
- 组件内部使用 useCallback 但是依赖没有填写或者填写不正确时
function Input(props) {
return <input onChange={props.onChange} />;
}
// 错误⽰例
function App() {
const [count, setCount] = useState(0);
// 缺少count依赖,导致只能拿到 0
const onChange = useCallback(() => { console.log(count); ... }, []);
return (
<div>
<Input onChange={onChange} />
</div>
);
}
// 正确⽰例
function App() {
const [count, setCount] = useState(0);
const onChange =() => { console.log(count); ... };
return (
<Input onChange={onChange} />
);
}
适合使用useCallback 场景
- 当子组件用memo 优化时
React.memo(function Input(props) {
return <input onChange={props.onChange} />;
}
);
// 正确⽰例
function App() {
const onChange = useCallback(() => {
...
}, [xxx]);
return ( <Input onChange={onChange} />
); }
- 当有多个地方调用同一块逻辑,并且有依赖项时
function App() {
const onChange = useCallback(() => {
...
}, [xxx]);
useEffect(() => {
onChange();
},[onChange]);
return (
<Input onChange={onChange} />
);
}