useMemo ,“创建”一个依赖函数。当其中一个依赖项更改时, useMemo重新计算记忆的值。而不需要在每个渲染进行昂贵的计算。
useMemo作用
useMemo 其实创建了一种数据缓存机制。比如登录页面需要向后台发送含用户名&密码的ajax请求,获取用户登录信息。useMemo 可以设置成只有当用户名密码改变后才向后台重新发送ajax,而在组件重新渲染时使用缓存的用户信息。
useMemo 与 useEffect 生命周期
useMemo 与 useEffect 作用类似,都会在依赖值改变时重新执行,但 useMemo 有一个缓存的返回值。
因此在组织渲染生命周期中,很自然地会把useMemo放到渲染DOM之前执行,如下:
useMemo => 渲染DOM => useEffect
示例:计数器
用我们之前创建的改变IP/PV计数的例子,useMemo和useEffect均不传参,即所有组件渲染时都重新执行,然后输出文字,为了方便演示,我们没有使用 useMemo 默认的返回值。
export function ExampleMemo () {
let [ ip, setIP ] = useState(0)
let [ pv, setPV ] = useState(0)
let memoMsg = 'useMemory here'
let effectMsg = 'useEffect here'
useEffect(()=>{
effectMsg = 'useEffect here:' + Date.now()
})
useMemo(()=>{
memoMsg = 'use Memo here:' + Date.now()
})
return (
<div>
<hr/><h1>useMemoEffect: IP:{ip}, PV:{pv}</h1>
<p>{memoMsg}</p>
<p>{effectMsg}</p>
<button onClick={()=>{ setIP(ip+1); setPV(pv+1) }}>Add IP</button>
<button onClick={()=>{ setPV(pv+1) }}>Add PV</button>
</div>
)
}
效果:
当点击Add IP或Add PV时,只有useMemo定义的变量会显示到界面上。由此可见,useMemo 是在DOM渲染之前执行的,而useEffect定义的变量没有起作用,则是在DOM渲染之后执行的。
依赖值变化
useMemo 标准用法如下,数组传入依赖的项:如下,如果IP没变,返回记住的值。
let memoIp = useMemo(()=>{
return 'useMemo ip here:' + Date.now()
}, [ip])
return (
<div>
<hr/><h1>useMemoEffect: IP:{ip}, PV:{pv}</h1>
<p>{memoMsg}</p>
<p>{effectMsg}</p>
<p>{memoIp}</p>
<button onClick={()=>{ setIP(ip+1); setPV(pv+1) }}>Add IP</button>
<button onClick={()=>{ setPV(pv+1) }}>Add PV</button>
</div>
)
上面的代码只有当点击: Add IP 时, memoIp 的显示值才会改变。
完整示例: https://codesandbox.io/s/flamboyant-lake-nros4?file=/src/ExampleMemoEffect.js
useCallback
useMemo和useCallback接收的参数都是一样,都是在其依赖项发生变化后才执行,都是返回缓存的值,区别在于useMemo返回的是函数运行的结果,useCallback返回的是函数。
useCallback(fn, deps) 与 useMemo(() => fn, deps). 是等价的,
相当于反函数存起来,由用户决定何时使用。