React.memo
React.memo 是一个高阶组件,对传入的 props 进行浅比较,从而来决定是否更新被包裹的组件。
import React, { useState } from "react";
const Child =() => {
console.log("render Child");
return <div>Child</div>
};
const Parent = () => {
const [count, setCount] = useState(0);
return (
<div>
<Child />
<div>count:{count}</div>
<button
onClick={() => {
setCount(count+1)
}}
>
Add
</button>
</div>
);
};
export default Parent;
如上图,父组件的 count 和 Child 组件没有关系,当我点击“Add”的时候,控制台却打印出 "render Child" 的信息,我们不希望子组件更新,这时候我们就可以用React.memo
import React, { useState } from "react";
const Child = React.memo(() => {
console.log("render Child");
return <div>Child</div>
});
const Parent = () => {
const [count, setCount] = useState(0);
return (
<div>
<Child />
<div>count:{count}</div>
<button
onClick={() => {
setCount(count+1)
}}
>
Add
</button>
</div>
);
};
export default Parent;
注意:React.memo 对于 props 的比较是浅比较,当一个引用类型的 props 改变时,只要它的地址没有发生改变,就算 props 中某一项数据发生了改变,被 memo 包裹的组件也不会重新渲染。
useMomo
如果一些值的计算量很大,那么可以用 useMemo来做一个缓存,只有依赖变化时才会重新计算,而不是每次渲染时都进行计算。
import React, { useState } from "react";
const Child = (props) => {
const { age = 0,name='' } = props;
const someComputer = ()=>{
console.log('some computer');
return age+10
}
return <div>
<div>age:{age}</div>
<div>name:{name}</div>
<div>{someComputer()}</div>
</div>;
};
const Parent = () => {
const [age,setAge] = useState(0);
const [name,setName] = useState('张三');
return (
<div className={styles.home}>
<Child age={age} name={name}/>
<button
onClick={() => {
setAge(age+1)
}}
>
Age加1
</button>
<button
onClick={() => {
setName('李四')
}}
>
改名
</button>
</div>
);
};
export default Parent;
上面的例子中,当我们点击“改名”按钮时,控制台打印了“some computer”,其实 Child 组建的 someComputer 并不需要更新,因为 someComputer 只依赖了 “age”,这时可以使用useMemo,
import React, { useState,useMemo } from "react";
const Child = (props) => {
const { age = 0,name='' } = props;
const someComputer = useMemo(()=>{
console.log('some computer');
return age+10
},[age])
return <div>
<div>age:{age}</div>
<div>name:{name}</div>
<div>{someComputer()}</div>
</div>;
};
const Parent = () => {
const [age,setAge] = useState(0);
const [name,setName] = useState('张三');
return (
<div>
<Child age={age} name={name}/>
<button
onClick={() => {
setAge(age+1)
}}
>
Age加1
</button>
<button
onClick={() => {
setName('李四')
}}
>
改名
</button>
</div>
);
};
export default Parent;
useCallback
useCallback 类似于 useMemo,只不过 useCallback 用于缓存函数,对于需要传递函数给子组件的场合,不使用 useCallback的话,子组件每次都会重新渲染
import React, { useState } from "react";
const Child = React.memo(() => {
console.log('render Child');
return <div>Child</div>;
});
const Parent = () => {
const [count,setCount] = useState(0);
const myOnClick = ()=>{}
return (
<div>
<Child myOnClick={myOnClick}/>
<button onClick={()=>{setCount(count+1)}}>加一</button>
</div>
);
};
export default Parent;
上面的代码中,当我们点击“加一”按钮时,控制台打印“render Child”,是因为我们更新了 Parent 组件的“count”值,从而导致 myOnClick 函数被重新生成,其实 myOnClick 并没有依赖 “count”,我们可以使用“useCallback”,进行优化,如下:
import React, { useCallback, useState } from "react";
const Child = React.memo(() => {
console.log('render Child');
return <div>Child</div>;
});
const Parent = () => {
const [count,setCount] = useState(0);
const myOnClick = useCallback(()=>{},[])
return (
<div>
<Child myOnClick={myOnClick}/>
<button onClick={()=>{setCount(count+1)}}>Add1</button>
</div>
);
};
export default Parent;