react性能优化

这是我参与更文挑战的第4天,活动详情查看:查看挑战

React更新机制

React 渲染流程:

image.png

React 更新流程:

image.png

React在props或state发生改变时,会调用React的render方法,会创建一颗不同的树。

情况一: 对比不同类型的元素

当节点为不同的元素,React会拆卸原有的树,并建新的树。

  • 卸载树时,对应的DOM会被销毁,组件实例将执行componentWillUnmount()钩子;
  • 创建新树,对应的DOM会被创建以及插入到DOM中,组件实例将执行componentDidMount()等钩子。

下例: React 会销毁 Counter 组件并且重新装载一个新的组件,而不会对Counter进行复用。

<div>
  <Counter />
</div>

<span>
  <Counter />
</span>
复制代码

情况二: 对比同一类型的元素

当比对两个相同类型的 React 元素时,React 会保留 DOM 节点,仅比对及更新有改变的属性。

如果是同类型的组件元素:

  • 组件会保持不变,React会更新该组件的props,并且调用 componentWillUpdate() 等钩子;
  • 下一步,调用 render() 方法,diff 算法将在之前的结果以及新的结果中进行递归。
// 只需要修改 DOM 元素上的 className 属性
<div className='before' title='yes' />
<div className='after' title='yes' />

// 只需要修改 DOM 元素上的 color 样式,无需修改 fontWeight。
<div style={{color:'red',fontWeight:'blod'}} />
<div style={{color:'green',fontWeight:'blod'}} />
复制代码

情况三:对子节点进行递归

在默认条件下,当递归 DOM 节点的子元素时,React 会同时遍历两个子元素的列表;当产生差异时,生成一个
mutation。

在列表最后插入一条数据:

  • 前面两两比较是完全相同的,不会产生mutation;
  • 最后一个比较,产生一个mutation,将其插入到新的DOM树后面。

在列表中间插入一条数据:

  • 在产生差异出开始,后面每条都不一样,产生多个mutation;
  • 对性能产生较大的问题;
  • 优化:对每条数据填写keys。

render函数调用

当嵌套多层组件,修改上层的state/props会导致render函数被调用,从而重新渲染。
如果修改state/props对子组件没有影响,子组件依旧会重新渲染,造成性能浪费

shouldComponentUpdate()

通过 shouldComponentUpdate()(简称:SCU),来控制是否需要执行render函数。

PureComponent

如果所有的类,我们都需要手动来实现 shouldComponentUpdate,会增加很多工作量。

react提供了一个类 PureComponent,可以帮我们进行判断是否需要执行render函数

  • PureCompnent内部是通过shallowEqual方法来判断的;
  • shallowEqual是浅层比较state/props判断shouldComponentUpdate返回true/false

高阶组件memo

对于函数式组件,可以使用memo,来进行判断是否执行render

import React, { Component, Fragment, memo, PureComponent } from "react";

const MemoHeader = memo(function Header() {
  console.log("MemoHeader 渲染");
  return <div>MemoHeader</div>;
});

function Header() {
  console.log("Header 渲染");
  return <div>我是Header</div>;
}

class PureFooter extends PureComponent {
  render() {
    console.log("PureFooter 渲染");
    return <div>我是PureFooter</div>;
  }
}

class Footer extends Component {
  render() {
    console.log("Footer 渲染");
    return <div>我是Footer</div>;
  }
}
class App extends Component {
  constructor() {
    super();
    this.state = {
      count: 0,
    };
  }
  render() {
    console.log("App 渲染");
    return (
      <Fragment>
        <MemoHeader />
        <Header />
        <div className="center">
          <h2>计数:{this.state.count}</h2>
          <button onClick={() => this.increment()}>+1</button>
        </div>
        <PureFooter />
        <Footer />
      </Fragment>
    );
  }
  increment() {
    this.setState({
      count: this.state.count + 1,
    });
  }
}

export default App;
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享