聊聊怎么利用Memoization提高React性能

本篇文章带大家了解一下Memoization,介绍一下为什么需要 Memoization,以及 React中实现 Memoization以提高性能的方法,希望对大家有所帮助!

聊聊怎么利用Memoization提高React性能

文章插图

在本教程中,我们将学习如何在 React 中实现 Memoization 。 Memoization 通过缓存函数调用的结果并在再次需要时返回这些缓存的结果来提高性能 。
我们将介绍以下内容:
    React 是如何渲染视图的?为什么需要 Memoization?如何在函数组件和类组件中实现 Memoization?注意事项
本文假设你对 React 中的类和函数组件有基本的了解 。
如果你想查阅这些主题,可以查看 React 官方文档 components and props
https://reactjs.org/docs/components-and-props.html

聊聊怎么利用Memoization提高React性能

文章插图

React 是如何渲染视图的?在讨论 React 中的 Memoization 细节之前,让我们先来看看 React 是如何使用虚拟 DOM 渲染 UI 的 。 【相关推荐:Redis视频教程】
常规 DOM 基本上包含一组用树的形式保存的节点 。 DOM 中的每个节点代表一个 UI 元素 。 每当应用程序中出现状态变更时,该 UI 元素及其所有子元素的相应节点都会在 DOM 树中更新,然后会触发 UI 重绘 。
在高效的 DOM 树算法的帮助下,更新节点的速度更快,但重绘的速度很慢,并且当该 DOM 具有大量 UI 元素时,可能会影响性能 。 因此,在 React 中引入了虚拟 DOM 。
这是真实 DOM 的虚拟表示 。 现在,每当应用程序的状态有任何变化时,React 不会直接更新真正的 DOM,而是创建一个新的虚拟 DOM 。 然后 React 会将此新的虚拟 DOM 与之前创建的虚拟 DOM 进行比较,找到有差异的地方(译者注:也就是找到需要被更新节点),然后进行重绘 。
根据这些差异,虚拟 DOM 能更高效地更新真正的 DOM 。 这样提高了性能,因为虚拟 DOM 不会简单地更新 UI 元素及其所有子元素,而是有效地仅更新实际 DOM 中必要且最小的更改 。
为什么需要 Memoization?在上一节中,我们看到了 React 如何使用虚拟 DOM 有效地执行 DOM 更新操作来提高性能 。 在本节中,我们将介绍一个例子,该例子解释了为了进一步提高性能而需要使用 Memoization 。
我们将创建一个父类,包含一个按钮,用于递增名为 count 的变量 。 父组件还调用了子组件,并向其传递参数 。 我们还在 render 方法中添加了 console.log() 语句:
//Parent.jsclass Parent extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } handleClick = () => { this.setState((prevState) => { return { count: prevState.count + 1 }; }); }; render() { console.log("Parent render"); return ( <div className="App"> <button onClick={this.handleClick}>Increment</button> <h2>{this.state.count}</h2> <Child name={"joe"} /> </div> ); }}export default Parent;此示例的完整代码可在 CodeSandbox 上查看 。
我们将创建一个 Child 类,该类接受父组件传递的参数并将其显示在 UI 中:
//Child.jsclass Child extends React.Component { render() { console.log("Child render"); return ( <div> <h2>{this.props.name}</h2> </div> ); }}export default Child;每当我们点击父组件中的按钮时,count 值都会更改 。 由于 state 变化了,因此父组件的 render 方法被执行了 。
传递给子组件的参数在每次父组件重新渲染时都没有改变,因此子组件不应重新渲染 。 然而,当我们运行上面的代码并继续递增 count 时,我们得到了以下输出:
Parent renderChild renderParent renderChild renderParent renderChild render你可以在这个 sandbox 中体验上述示例,并查看控制台的输出结果 。
从输出中,我们可以看到,当父组件重新渲染时,即使传递给子组件的参数保持不变,子组件也会重新渲染 。 这将导致子组件的虚拟 DOM 与以前的虚拟 DOM 执行差异检查 。 由于我们的子组件中没有变更且重新渲染时的所有 props 都没有变,所以真正的 DOM 不会被更新 。
真正的 DOM 不会进行不必要地更新对性能确实是有好处,但是我们可以看到,即使子组件中没有实际更改,也会创建新的虚拟 DOM 并执行差异检查 。 对于小型 React 组件,这种性能消耗可以忽略不计,但对于大型组件,性能影响会很大 。 为了避免这种重新渲染和虚拟 DOM 的差异检查,我们使用 Memoization 。

推荐阅读