React.memo & useMemo
React.memo
React.memo()
是一个高阶组件 (HOC),它接收一个组件 A 作为参数并返回一个组件 B,如果组件 B 的 props(或其中的值)没有改变,则组件 B 会阻止组件 A 重新渲染 。
简单来说,memo
就是对传入的组件做了缓存,如果组件的 props 没有改变,那么就不会 re-render。值的注意的是对比是否改变是通过 Object.is
来完成的。
一些情况下仍然会 re-render:
- 组件内部的 state 变更
- 组件被外部的 context 影响
Context.Provider
语法
const MemoizedComponent = memo(SomeComponent, arePropsEqual?)
SomeComponent
:需要 memoization 的组件arePropsEqual
:自定义比较函数
例子
- 如果没有增加
memo()
,那么当 name 和 address 任意一个改变时,Greeting 都会渲染。 - 而如果加上了
memo()
,则只有 name 修改时才会使 Greeting 重新渲染。
jsx
import { memo, useState } from 'react';
export default function MyApp() {
const [name, setName] = useState('');
const [address, setAddress] = useState('');
return (
<>
<label>
Name{': '}
<input value={name} onChange={e => setName(e.target.value)} />
</label>
<label>
Address{': '}
<input value={address} onChange={e => setAddress(e.target.value)} />
</label>
<Greeting name={name} />
</>
);
}
const Greeting = memo(function Greeting({ name }) {
console.log('Greeting was rendered at', new Date().toLocaleTimeString());
return (
<h3>
Hello{name && ', '}
{name}!
</h3>
);
});
useMemo
jsx
const [count, setCount] = useState(0);
const userInfo = {
// ...
age: count,
name: 'abc'
}
return <UserCard userInfo={userInfo}>
上面代码在执行时,每次渲染都会创建一个新的 userInfo
,即使与 old userInfo
值是一致的。这样 memo()
的优化就会失效。
因此我们可以得到结论,props 中如果传入的是引用对象,那么 memo()
优化就会失效。
jsx
const [count, setCount] = useState(0);
const userInfo = useMemo(() => {
return {
// ...
name: "abc",
age: count
};
}, [count]);
return <UserCard userInfo={userInfo}>
通过 useMemo 优化后,每次渲染时这个对象是不会改变的,仅依赖的 count 发生变化后,才会创建新的对象。