React Hooks 中的 useCallback 其实并不能避免 function 在 render 时的 allocation
1 2 3 4 5 6 7 8 9 10 11 12 13
| const FC = () => { const [visible, setVisible] = useState(false)
const handleShow = () => setVisible(true) const handleHide = () => setVisible(false)
return ( <> <button onClick={handleShow}>hide</button> <button onClick={handleHide}>hide</button> </> ) }
|
上面的例子中,每次 FC 的渲染都会重新定义一次,handleShow
和 handleHide
两个 function
借助 useCallback
可以改写为:
1 2 3 4 5 6 7 8 9 10 11 12 13
| const FC = () => { const [visible, setVisible] = useState(false)
const handleShow = useCallback(() => setVisible(true), []) const handleHide = useCallback(() => setVisible(false), [])
return ( <> <button onClick={handleShow}>hide</button> <button onClick={handleHide}>hide</button> </> ) }
|
实际上,这样组件的性能会更差,因为 useCallback 并不能阻止这两个 function 被重新定义,反而增加了运算量:
1
| const handleShow = useCallback(() => setVisible(true), [])
|
可以拆解成
1 2
| const handleShow = () => setVisitble(true) React.useCallback(handleShow, [])
|
比原来还多一步
真正需要 useCallback 的情形
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| const FC = () => { const [visible, setVisible] = useState(false)
const handleShow = useCallback(() => setVisible(true), []) const handleHide = useCallback(() => setVisible(false), [])
return ( <> <Button onClick={handleShow}>show</Button> <Button onClick={handleHide}>hide</Button> </> ) }
const Button = (props) => { const { onClick } = props
useEffect( () => { console.log(onClick) // 每次 onClick 改变,做些什么 }, [onClick] )
return ( <button onClick={onClick}>{props.children}</button> ) }
|
上面的这种情况,在 <Button>
组件中,用到了 useEffect
。 而 useEffect
对于对象类型的 props
是比较他们的 reference
,来判断要不要执行。
如果在 FC
中没有用 useCallback
,那么每次 FC
的渲染都会定义全新的 handleShow
(每次的 reference
都不一样),所以都会在 <Button>
中触发 console.log(onClick)
。
所以 useCallback
就是用来控制相同的依赖参数下,是否需要保持这个 funciton 的 reference
,而他并不能避免重新定义这个 function。
相关链接:When to useMemo and useCallback