React缓存,探讨memo函数如何缓存阻止(子)组件渲染?
发布于 作者:苏南大叔 来源:程序如此灵动~ 我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...
React
里面比较高阶的使用方式:memo()
函数是本文的主要内容。memo
和useMemo()
看起来很相似,使用上却有很大的区别。useMemo()
作用在函数之上,是对昂贵运算逻辑函数结果的缓存,只能在函数式组件里面使用。memo
作用在组件之上,是对组件的缓存,函数式组件类组件,都是其作用对象。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0
,create-react-app@5.0.1
,react-router-dom@6.27.0
,react@18.3.1
。
memo高阶函数
memo()
直接套用在组件上,无关组件的写法是函数式写法,还是类写法,都可以使用memo()
高阶函数。它对组件为目标进行缓存,根据props
决定是否执行渲染。主打的就是(子)组件无渲染无变化。
- 默认情况下,如果传入组件的所有属性,都保持一致。那么,这个组件就没有渲染的必要性。
- 当然,也可以自定义函数来对前后的属性进行对比。来自行决定是否渲染。
return false
渲染,true
不渲染。 - 其中特殊的地方就是传入属性是函数定义的时候,表面上是同样的函数,但是如果内存地址不一样的话。也是会被判定为非相同的值的。会被执行渲染。【待续】
测试代码
在下面的测试代码中,一共有五个子组件Child
被加载。其中四个被memo
高阶函数所包裹。每个子组件里面都输出了数字时间戳,父组件刷新的时候,如果这些数字时间戳没有变化,那么就证明对应的子组件被缓存了,并没有发生再次渲染。
import React, { useState } from "react";
function Child() {
console.log("child render");
return <>{Date.now().toString().slice(-6)}</>;
}
const MemoChild = React.memo(Child);
const MemoChild2 = React.memo(Child, (prev, next) => {
if (next.point > 110) {
return false;
}
return true;
});
export default function App() {
console.log("parent render");
const [info, setInfo] = useState({
name: "sunan大叔",
point: 100,
});
// const setInfo2 =()=>{}
function setInfo2() {}
return (
<div>
<div>
【{info.name}】, 中奖率:{info.point}%
<button
onClick={() => {
setInfo({ ...info, point: info.point + 1 });
}}
>
幸运得分
</button>
</div>
<div>
<table>
<tbody>
<tr>
<td>【组件1】</td>
<td>
<Child></Child>
</td>
<td>恒定渲染, 父变子就变</td>
</tr>
<tr>
<td>【组件2】</td>
<td>
<MemoChild fn={setInfo2}></MemoChild>
</td>
<td>恒定渲染, memo, 父组件每次都渲染, 该函数属性随父组件渲染重新定义</td>
</tr>
<tr>
<td>【组件3】</td>
<td>
<MemoChild2 point={info.point}></MemoChild2>
</td>
<td>有条件渲染, memo, 自定义规则渲染, 先不变(false)后变(true)</td>
</tr>
<tr>
<td>【组件4】</td>
<td>
<MemoChild></MemoChild>
</td>
<td>恒定不渲染, memo, 无属性无规则, 默认被Memo</td>
</tr>
<tr>
<td>【组件5】</td>
<td>
<MemoChild fn={setInfo}></MemoChild>
</td>
<td>恒定不渲染, memo, setInfo是useState的导出函数, 不变</td>
</tr>
</tbody>
</table>
</div>
</div>
);
}
表格总结
父组件重新渲染的时候,子组件也会即将触发渲染。但是,memo
高阶函数,给其包裹的子组件一次选择的机会。如果变化前后的各个属性props
没有发生变化,则拒绝渲染。当然,这个规则也可以自定义,根据需要来决定是否渲染。其中,有个容易踩坑的地方,就是如果传入props
的属性是个函数的时候,这个函数可能是每次都重新生成的。这个时候,子组件会被渲染。
序号 | 子组件 | 是否Memo | props属性 | 是否渲染 |
---|---|---|---|---|
1 | <Child /> | 否 | 无 | 恒定渲染 |
2 | <MemoChild fn={fn} /> | 是 | fn是个变化的函数 | 恒定渲染 |
3 | <MemoChild2 point={p} /> | 是 | point是个变化的数字 | 有条件渲染 |
4 | <MemoChild /> | 是 | 无任何属性 | 恒定不渲染 |
5 | <MemoChild fn={fn2} /> | 是 | fn不变是个useState导出 | 恒定不渲染 |
相关文章
memo
函数的相关文章:
如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。