https://juejin.cn/post/6844904101445124110#heading-6
useCallback 的作用
useCallback是用来优化性能的,
但是,如果不了解它是怎么优化性能的,建议还是不要用了,因为,容易出现bug。
useCallback返回一个函数,只有在依赖项变化的时候才会更新(返回一个新的函数)。
import React, { useState, useCallback } from 'react'; import Button from './Button'; export default function App() { const [count1, setCount1] = useState(0); const [count2, setCount2] = useState(0); const [count3, setCount3] = useState(0); const handleClickButton1 = () => {setCount1(count1 + 1)}; const handleClickButton2 = useCallback(() => { setCount2(count2 + 1); }, [count2]); return ( <div> <div> <Button onClick={handleClickButton1}>Button1</Button> </div> <div> <Button onClick={handleClickButton2}>Button2</Button> </div> <div> <Button onClick={() => {setCount3(count3 + 1); }}> Button3 </Button> </div> </div> ); } 链接:https://juejin.cn/post/6844904101445124110
// Button.jsx import React from 'react'; const Button = ({ onClickButton, children }) => { return ( <> <button onClick={onClickButton}>{children}</button> <span>{Math.random()}</span> </> ); }; export default React.memo(Button);
在案例中可以分别点击Demo中的几个按钮来查看效果:
- 点击 Button1 的时候只会更新 Button1 和 Button3 后面的内容;
- 点击 Button2 会将三个按钮后的内容都更新;
- 点击 Button3 的也是只更新 Button1 和 Button3 后面的内容。
经过useCallback优化后的 Button2 是点击自身时才会变更(更新),其他的两个只要父组件更新后都会变更(这里Button1 和 Button3 其实是一样的,无非就是函数换了个地方写)。
注:Button组件里面的React.memo这个方法,会对props做一个浅层比较,如果props没有发生改变,则不会重新渲染此组件。没有用useCallback包括的函数,每次都会重新声明一个新的方法,新的方法尽管和旧的方法一样,但是依旧是两个不同的对象,React.memo对比后发现对象props改变,就重新渲染了。
用useCallback包括的函数,根据依赖是否发生变化,才会决定是否返回一个新的函数,如果没有变化,就会返回上一次缓存的函数。
const [count1, setCount1] = useState(0); const [count2, setCount2] = useState(0); const handleClickButton1 = () => { setCount1(count1 + 1) }; const handleClickButton2 = useCallback(() => { setCount2(count2 + 1) }, [count2]); return ( <> <button onClick={handleClickButton1}>button1</button> <button onClick={handleClickButton2}>button2</button </> )
上面这种写法在当前组件重新渲染时 handleClickButton1
函数会重新渲染,handleClickButton2
useCallback 里面的函数也会重新渲染。反而加了 useCallback ,在执行的时候还多了 useCallback 中对 count2
的一个比较逻辑。
useCallback 是要配合子组件的 shouldComponentUpdate
或者 React.memo
一起来使用的,否则就是反向优化,这就是前面说的bug。
useMemo 的作用
useMemo是在render期间执行的。所以不能进行一些额外的副操作,比如网络请求等。
传递一个创建函数和依赖项,创建函数会需要返回一个值,只有在依赖项发生改变的时候,才会重新调用此函数,返回一个新的值。
没有用useMemo
// ... const [count, setCount] = useState(0); const userInfo = { // ... age: count, name: 'Jace' } return <UserCard userInfo={userInfo}>
用了useMemo
// ... const [count, setCount] = useState(0); const userInfo = useMemo(() => { return { // ... name: "Jace", age: count }; }, [count]); return <UserCard userInfo={userInfo}>
第一段没有用useMemo的代码,userInfo 每次都将是一个新的对象,无论 count
发生改变没,都会导致 UserCard 重新渲染,而下面的则会在 count
改变后才会返回新的对象。
怎么用useMemo表示useCallback
useCallback(fn,[m]);
等价于
useMemo(() => fn, [m]);
结语
useCallback缓存的是函数,useMemo 缓存的是函数的返回就结果。
useCallback 是来优化子组件的,防止子组件的重复渲染。
useMemo 可以优化当前组件也可以优化子组件,优化当前组件主要是通过 memoize 来将一些复杂的计算逻辑进行缓存。当然如果只是进行一些简单的计算也没必要使用 useMemo。