概述
useMemo
是React 中的一个HOOK
,用于根据依赖在每次渲染时候缓存计算
结果;
大白话就是,只有依赖项发生变化时候,才会重新渲染为新计算的值,否则就还是取原来的值,有点类似 vue 中的 computed
计算属性,注意与 useEffect 区分;
写法
const value = useMemo(fnc, [a,b])
第一个参数:fnc
是一个函数,用于根据 依赖项 a、b变化时候触发计算得出新值,必须是一个没有任何参数的纯函数,可以返回任意类型;若 a、b没有变化,则React 返回与上次相同的值;若 a、b 发生改变,则会返回新的值;
第二个参数:[a、b]
是一个数组,函数 fnc中计算所依赖的值
,这个数组中若不传入具体变量,而是传入 空数组[],那么会在组件每次更新时候重新渲染;
这种缓存值的方式叫做 记忆化 (memoization)
, 这也是这个Hook 称为 useMemo 的由来;
使用场景
1、当我们在 useMemo
中的代码运行很慢,通过使用 useMemo
运行效率得到显著提升;
2、将计算结果作为 props
传递给包裹在 memo
中的组件。当计算结果没有改变时,你会想跳过重新渲染。记忆化让组件仅在依赖项不同时才重新渲染。
3、你传递的值稍后用作某些 Hook
的依赖项。例如,也许另一个 useMemo
计算值依赖它,或者 useEffect
依赖这个值。
例如:
将计算结果作为 props 传给子组件
// 父组件
import React, {useMemo, useState} from 'react'
import ChildA from './childA'
export default function MyMemo() {
const [firstName, setFirstName] = useState('Andy')
const [lastName, setLastName] = useState('Li')
const [count, setCount] = useState(0)
const fullName = useMemo(() => {
console.log('==useMemo==')
return firstName +'' + lastName
}, [firstName, lastName]) // 第二个参数是数组,表示fullName 依赖 firstName 和 lastName 的值,只有 firstName 和 lastName 值发生变化,fullName 才重新计算
const handleChangeName = (e, type) => {
console.log('==handleChangeName==', e)
// [`set${type}`](e.target.value)
// if (type === 'FirstName') {
// setFirstName(e.target.value)
// } else {
// setLastName(e.target.value)
// }
}
const handleChangeFirstName = () => {
console.log('==更新第一个名称=')
setCount(count+1)
setFirstName(11)
}
return (
<div>
<input type="text" value={firstName} onChange={(e) => handleChangeName(e, 'FirstName')} />
<p>点击了{count}次</p>
<button onClick={handleChangeFirstName}>firstName</button>
<br/>
<input type="text" value={lastName} onChange={(e) => handleChangeName(e, 'LastName')} />
<hr />
<ChildA fullName={fullName}></ChildA>
</div>
)
}
// 子组件
import React, {memo, useState} from 'react'
const ChildA = memo(({fullName}) =>{
console.log('=render=ChildA==fullName----', fullName)
return (
<div>
<p>全称:{fullName}</p>
</div>
)
})
export default ChildA
通过 log日志,我们可以发现,共计点击了 firstName
按钮 18次;只有在初始化和第一次点击时候才会渲染 子组件;
因为第一次点击将 firstName
更新为 11;之后的点击传入相同的值 11
,导致 useMemo 返回的 fullName 是相同的,故不再进行渲染
而当我们使用 useEffect
时候,会每次都更新子组件
注意:
1、useMemo
只能作为组件代码性能优化
使用,如果在不使用 useMemo
时,代码无法正常运行,那么我们需要先排查问题,之后再使用 useMemo
;
2、避免不必要的更新 state 的 Effect
;React 中很多的性能是由于其自身的更新链导致的,所以我们要避免重复的更新同一个组件
;
3、尽可能的减少依赖项
,避免过多的依赖导致代码难以理解,难以追踪问题;我们可以将依赖项 设置成 state;
4、我们应该减少状态的提升
,多使用state,而不是滥用useMemo来处理性能;