要想学习useMemo必须要先知道React.memo
这两者都有一定的优化作用
memo的作用
当数据变化时,代码会重新执行一遍,但是子组件数据没有变化也会执行,这个时候可以使用memo将子组件封装起来,让子组件的数据只在发生改变时才会执行
案例
点击按钮改变n的值,m不变,验证程序会不会执行m的代码
不使用memo的情况
只改变n的值时,虽然说m的值没变,但是也执行了Child的打印语句
function App(){ const [n,setN] = useState(0); const [m,setM] = useState(0); const add=()=>{ setN(i=>i+1); }; const addChild=()=>{ setM(i=>i+1); }; return( <div> <div> n:{n} <button onClick={add}>n+1</button> <button onClick={addChild}>m+1</button> </div> <Child data={m} /> </div> ) } function Child(props){ console.log('child执行了') return( <div> child:{props.data} </div> ) } ReactDOM.render(<App />,document.getElementById('root'));
使用memo进行封装
将Child用memo封装一下,就可以使m不变就不执行Child,这个时候只要m的值不变,就不会执行Child组件
使用React.memo封装,会返回一个新的组件,调用新组件
function Child(props){ console.log('child执行了') return( <div> child:{props.data} </div> ) } // 封装child const Child2 = React.memo(Child) ReactDOM.render(<App />,document.getElementById('root'));
但是此时还有一个bug,如果在子组件Child上添加一个监听函数,无论修改m的值与否,都会执行Child组件
function App(){ const [n,setN] = useState(0); const [m,setM] = useState(0); const add=()=>{ setN(i=>i+1); }; const addChild=()=>{ setM(i=>i+1); }; + const onClickChild=()=>{ }; return( <div> <div> n:{n} <button onClick={add}>n+1</button> <button onClick={addChild}>m+1</button> </div> + <Child2 data={m} onClick={onClickChild} /> </div> ) } function Child(props){ console.log('child执行了') console.log('这里有很多代码') return( + <div onClick={props.onClick}> child:{props.data} </div> ) } const Child2 = React.memo(Child)
当点击n时,就会重新执行App代码,onClickChild
空函数的地址会发生改变,所以说此时还是会执行Child的
而useMemo正是解决这个问题的
useMemo的作用
解决因函数更新而渲染自己的问题,就可以使用useMemo,使用它将函数重新封装
const onClickChild=useMemo(fn,array)
监听变量,第一个参数是函数,第二个参数是依赖,只有依赖变化时才会重新计算函数
import React, { useMemo, useState } from 'react' import ReactDOM from 'react-dom' //其他的代码不变,只需要重写m的点击函数 //使用useMemo重新写监听函数,当m变化时才会执行此代码 const onClickChild=useMemo(()=>{ return ()=>{ console.log(m) } },[m])
也可以把useMemo替换成useCallback,使用useCallback就不用写return函数了
const onClickChild=useMemo(()=>{ return ()=>{ console.log(m) } },[m]) //等价于 const onClickChild=useCallback(()=>{ console.log(m) },[m])
注意:
- 如果你的value是个函数,那么你就要写成
useMemo(()=>(x)=> console.log(x))
- 这是一个返回函数的函数,比较复杂;于是就有了
useCallback
,你可以使用useCallback