在我的理解中, useMemo 是传入创建函数和变化依赖,根据依赖变化(浅对比)来确定是返回一个新的值还是之前的值。请看下面例子来验证我的理解:
import React, {
ReactElement, useEffect, useMemo } from "react";
const Child1: React.FC = () => {
console.log("渲染了一次本组件");
/** 普通对象 */
const commonObjectRef = React.useRef<ReactElement>();
/** useMemo对象 */
const memoObjectRef = React.useRef<ReactElement>();
/** 组件是否主动触发过一次刷新 */
const [isRefred, setIsRefreshed] = React.useState<boolean>(false);
/** 声明普通对象 */
const commonObject = <span>普通对象</span>;
/** 声明memo 包裹的对象 */
const memoObject = useMemo(() => <span>memo对象</span>, []);
useEffect(() => {
if (!commonObjectRef.current) {
commonObjectRef.current = commonObject;
}
if (!memoObjectRef.current) {
memoObjectRef.current = memoObject;
}
console.log("普通对象是否相等:", commonObjectRef.current === commonObject);
console.log("memo对象是否相等:", memoObjectRef.current === memoObject);
// 触发一次渲染本组件
if (!isRefred) setIsRefreshed(true);
}, [isRefred]);
return <div>是否刷新过一次页面:{
isRefred ? "是" : "否"}</div>;
};
export default Child1;
在 React 函数里面,如果父组件更新,要让子组件不更新,需要满足两个条件:
针对第一条,利用刚才在 useMemo 的表现描述中能够想到: 保持地址引用不变,我们只需要用 useMemo 返回这个子组件,依赖数组传入它的更新依赖就可以了。(注: 如果直接在父组件 return
针对第二条,简单数据类型来说,只要他们值是相等的,就可以认为是没有变化。复杂数据类型对象(数组、对象、函数)来说,在父组件函数内部声明的复杂数据对象都是新的,此时浅对比下 React 认为组件发生了变化需要更新。我们要做的是返回旧的对象从而满足第二个条件。
所以为了满足两个条件,我们可以使用 useMemo 包裹返回不变的对象(组件、数组、对象、函数),使用 useCallback 返回一个不变的函数。(注: 我没有验证过,但我觉得 useMemo 返回一个函数功能应该和 useCallback 效果是一样的,只是语义化效果不好,哈哈)。
import React from "react";
import ReactDOM from "react-dom";
import Child1 from "./component/child1/child1";
import Child2 from "./component/child2/child2";
const Father = () => {
console.log("更新父组件");
const [count, setCount] = React.useState<number>(0);
React.useEffect(() => {
const Fresh = () => {
setTimeout(() => {
setCount((count) => count + 1);
Fresh();
}, 1000);
};
Fresh();
}, []);
return (
<div>
<p>父组件更新计数:{
count}</p>
<Child1 />
{
React.useMemo(
() => (
<Child2 />
),
[]
)}
</div>
);
};
ReactDOM.render(<Father />, document.getElementById("root"));
import React from "react";
const Child1: React.FC = () => {
console.log("更新子组件1");
return <div>子组件1</div>;
};
export default Child1;
import React from "react";
const Child2: React.FC = () => {
console.log("更新子组件2");
return <div>子组件2</div>;
};
export default Child2;
执行结果:
可以看到