React.memo 是什么?

在写函数式组件的时候,为了避免无效的渲染,可以通过 React.memo 函数来实现,类似于 React.PureCompnent 的功能,对 props 进行浅比较,代码如下

function MyComponent(props) {}
function areEqual(prevProps, nextProps) {
// 手动判断是否需要重新渲染
// return true不渲染,false则渲染
}
export default React.memo(MyComponent, areEqual);

React.memo 第二个参数不用的话默认就 props 浅比较

React.memo 在跟某些 hooks 配合使用的情况下会失效,例如在组件内部使用 useStateuseReduceruseContext ,当 state 或者 context 改变时,组件还是会重新渲染

React.memo 和 useContext

在配合 useContext 使用的情况下,当 context 变化,函数组件会重新渲染,如何解决呢?

避免 context 的值太过于复杂,尽量拆分细粒度的 context 值

拆分组件多个 context,比如 AppContext,ThemeContext,AudioContext 等等,这样其他 context 改变就不会导致无关组件的渲染

function Button() {
let theme = useContext(ThemeContext);
return <ExpensiveTree className={theme} />;
}

拆分组件,与使用 context 组件分离,在 render 阶段单独通过 memo 来缓存组件

const Button = () => {
const { theme } = useContext(ThemeContext);
return <button>click {theme}</button>;
};
export default momo(Button);

改写为

const ThemeButton = memo(({ theme }) => {
return <button>click {theme}</button>;
});
const Button = () => {
const { theme } = useContext(ThemeContext);
return <ThemeButton theme={theme} />;
};
export default Button;

配合 useMemo 来渲染组件

function Button() {
let { theme } = useContext(AppContext);
return useMemo(() => {
return <ExpensiveTree className={theme} />;
}, [theme]);
}