父子组件的渲染规律
因为子组件是父组件的一部分,默认父组件发生变化时候子组件也会重新渲染。
react.memo的提出
但是当子组件状态变化触发重新渲染时,父组件不会重新触发,因为为避免不必要的渲染,会缩在最小范围内。就不会让父组件也发生重新渲染。 但是如果子组件非常复杂,还要在每次父组件重新渲染的时候跟着被渲染,就会产生 无意义的损耗。 为此,用react.memo来缓存子组件,当子组件的状态没变化时候就不用重新渲染。当子组件真的变化了,再重新渲染,重新缓存。
使用方法:
从react中解构出来memo const {memo}=react
用memo包裹子组件
js
const Child=memo(()=>{
return <>
<h1>{count}</h1>
<button onClick={()=>setcount(count+1)}>+</button>
<button onClick={()=>setcount(count-1)}>-</button>
</>
})
意思就是memo括号中的整个作为一个参数,memo就返回一个已经缓存化/记忆化的这样一个组件child。 父组件里面不变,直接用<child/>
重新缓存的情况:
- props组件嵌套属性改变
- state组件自身状态改变
- useContext跨组件通信数据改变
重新缓存失败的情况:
-
复杂数据类型(引用类型) :数组 (
arr
)、函数 (fn
)、对象等是通过引用地址 传递的。每次父组件重新渲染时,即使内容未变,这些值也会被重新创建 ,导致内存地址变化,React.memo
的浅比较会认为 props 发生了变化,从而触发子组件重新渲染。 -
简单数据类型(原始类型) :如
string
、number
、boolean
、null
、undefined
、symbol
等,直接比较值是否相同,不会因内存地址问题引发重新渲染。 -
解决方法:
-
- 使用
useMemo
缓存数组/对象
避免父组件每次渲染时重新创建引用:
iniconst memoizedArr = useMemo(() => [1, 2, 3], []); <ChildComponent arr={memoizedArr} />
- 使用
-
使用
useCallback
缓存函数确保函数引用不变:
iniconst memoizedFn = useCallback(() => {}, []); <ChildComponent fn={memoizedFn} />
-
自定义
areEqual
比较函数手动控制
React.memo
的 props 比较逻辑:csharpconst areEqual = (prevProps, nextProps) => { return prevProps.arr.join() === nextProps.arr.join(); }; export default React.memo(ChildComponent, areEqual);