前言
什么是react的memo,简单来说就是父组件改变时,子组件也会跟着重新渲染(子组件没有用父组件改变了的值),这时我们就要利用memo规避一些无用的页面渲染。
我们可以通过三种方式规避一些无用的渲染:
- 类组件的两种方式:
shouldComponentUpdate
PureComponnet - 函数组件的一种方式:
memo
memo(Component, arePropsEqual?)
参数
Component
:要进行记忆化的组件。memo
不会修改该组件,而是返回一个新的、记忆化的组件。它接受任何有效的 React 组件,包括函数组件和 forwardRef 组件。可选参数
arePropsEqual
:一个函数,接受两个参数:组件的前一个 props 和新的 props。如果旧的和新的 props相等,即组件使用新的 props 渲染的输出和表现与旧的 props 完全相同,则它应该返回 true。否则返回 false。通常情况下,你不需要指定此函数。默认情况下,React 将使用 Object.is 比较每个 prop。
用法
React.memo
仅检查 props
变更。如果函数组件被 React.memo
包裹,且其实现中拥有 useState
或 useContext
的 Hook,当 context 发生变化时,它仍会重新渲染。
默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。
当 props 没有改变时跳过重新渲染
在此示例中,请注意 Greeting 组件在 name
更改时重新渲染(因为那是它的 props 之一),但是在 address
更改时不会重新渲染(因为它不作为 props 传递给 Greeting
)
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>;
});
最小化 props 的变化
当你使用 memo
时,只要任何一个 prop 与先前的值不是 浅层相等 的话,你的组件就会重新渲染。这意味着 React 会使用 Object.is
比较组件中的每个 prop 与其先前的值。注意,Object.is(3, 3)
为 true,但 Object.is({}, {})
为 false。
为了最大化使用 memo 的效果,应该尽量减少 props 的变化次数。例如,如果 props 是一个对象,可以使用 useMemo
避免父组件每次都重新创建该对象:
function Page() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
const person = useMemo(
() => ({ name, age }),
[name, age]
);
return <Profile person={person} />;
}
const Profile = memo(function Profile({ person }) {
// ...
});
指定自定义比较函数
在极少数情况下,最小化 memoized 组件的 props 更改可能是不可行的。在这种情况下,你可以提供一个自定义比较函数,React 将使用它来比较旧的和新的 props,而不是使用浅比较。这个函数作为 memo
的第二个参数传递。它应该仅在新的 props 与旧的 props 具有相同的输出时返回 true;否则应该返回 false
。
function Child({value}){
console.log('I am rendering');
return (
<div>{value}</div>
)
};
function areEqual(prevProps, nextProps) {
if(prevProps.value===nextProps.value){
return true
}else {
return false
}
}
export default React.memo(Child,areEqual)
总结
memo
会检测props到改变来决定组件是否需要进行重新渲染,换言之就是,被memo
函数包起来的组件只有本身的props被改变之后才会重新渲染memo
只能进行浅比较来校验决定是否触发重新渲染。- 即使使用
memo
,React组件自己的state
或正在使用的context
发生更改,组件也会重新渲染。 memo
需要选择那些经常被重新渲染的组件有选择性的去缓存。