React.memo(明智地使用我)
React.memo
是一个相当简单但被误解的高阶组件。通过文档我们得到这样的定义:
如果你的函数组件在给定相同 props 的情况下渲染相同的结果,你可以将其包装在对 React.memo 的调用中,以便在某些情况下通过记忆结果来提升性能。这意味着 React 将跳过渲染组件,并重用上次渲染的结果。
性能提升🤩?哇,那就让我们把一切都记录下来吧!
⚠️ 冷静下来,夏洛克,明智地使用它。
首先,让我们深入了解一下内部发生了什么神奇的事情。memo
当我说它很简单时,在查看了React repo 中的代码后,你一定会同意我的说法。整个代码基本上是这样的:
const REACT_MEMO_TYPE = Symbol.for('react.memo');
export function memo<Props>(
type,
compare?: (oldProps: Props, newProps: Props) => boolean
) {
const elementType = {
$$typeof: REACT_MEMO_TYPE,
type,
compare: compare === undefined ? null : compare,
};
return elementType;
}
所以这意味着当你使用它SomeComponent
并传递它时你基本上会得到回报:
{
$$typeof: Symbol.for('react.memo'),
type: SomeComponent,
compare: compare || null,
}
这意味着,如果你直接使用它,你会得到同样的结果,不相信吗?在codesandbox中试试吧。
你会注意到, for 有第二个参数memo
,它是一个compare
函数。让我们再看一下文档:
默认情况下,它只会对 props 对象中的复杂对象进行浅层比较。如果你想控制比较过程,也可以提供自定义比较函数作为第二个参数。
这意味着,即使 props 发生变化,我们也可以决定组件是否应该重新渲染。假设你不希望组件在第一次渲染后再次重新渲染(无论出于什么原因),你可以简单地这样做:
const MemoComponent = React.memo(({ name }) => {
return <div>{name}</div>;
}, () => true);
⚠️ 注意,我在比较函数中返回的是true
,我基本上是在说,之前有意义的 props 与下一个 props 相同,所以它不应该重新渲染。(它基本上是 的逆shouldComponentUpdate
)
那么什么时候该正确使用它呢?主要当你的组件是纯函数式组件,并且/或者它总是使用相同的 props 进行渲染,并且你想控制它是否应该渲染时,你应该使用它。例如,假设你有以下组件:
const UserInfoHeader = ({avatar, name}) => (
<>
<img src={avatar} />
<div>Hi {name}</div>
</>
)
您可能会在某些仪表板中使用它,这是一个绝佳的使用机会memo
,您的仪表板可能会重新渲染并更改几个内部状态,但不太可能更改名称或头像源,因此UserInfoHeader
使用 React.memo 包装将避免此处不必要的渲染。
现在我们对它有了更好的理解,但是如果我们用 包裹所有内容,会有什么问题呢memo
?什么时候应该避免这种情况?
不明智地使用memo
会导致难以调试的错误,并给人一种提高性能的错觉。那么问题是什么时候不该使用React.memo
?
1. 道具经常更换
React.memo
每次渲染时比较 props 是有成本的,如果你的组件一直在更新 props,你可能会损失性能,因为普通组件不会关心它,只会正常重新渲染。
2. 比较函数开销太大
假设你有一个复杂的对象作为 prop 传递,并且你想进行一次非常昂贵的计算来比较前一个对象和新对象。注意,与简单的始终重新渲染相比,这样做可能会降低性能。
3. 接收函数作为 props 的组件
这不是什么禁忌,但在记忆组件中使用回调时要小心,例如:
const Input = React.memo(...)
const App = () => (<Input onChange={(e) => { console.log(e) }} />)
在这种情况下,Input
无论如何都会重新渲染,因为在每次App
渲染中我们都会重新定义,onChange
所以Input
要么在这里使用静态函数,要么将其与结合起来useCallback
以防止它发生。
总结
React.memo
它是一个功能强大且易于使用的 HOC,可以提升性能,但误用可能会适得其反,甚至损害性能。请务必谨慎使用,并使用一些性能分析工具来确保其用例有效。
你有什么好的使用示例吗?memo
或者你遇到过相关的 bug 吗?请在评论区分享。:)