react点击改变样式_深入探究React性能优化

b9f198ffb1342a43d7d767253bb3c0ff.png

探究React 性能优化

React为设计高性能的React应用程序提供了很多优化,可以通过遵循一些最佳实践来实现。性能优化的关键在于是否能够减少不必要的Render,触发Render主要有下面的情况:

  • 发生setState。
  • props的改变。
  • 使用forceUpdate

下面给出了一些常见的优化方案,我们将解读、实践它们,对于部分内容我们会深入源码分析其原理。

React.PureComponent

组件嵌套造成的额外渲染

案例

来看下面这个组件嵌套的代码:

import React from "react";

class Footer extends React.Component {
  render() {
    console.log("Footer component render!");
    return (
      <div>Footer组件</div>
    )
  }
}

const List = () => {
  console.log("List component render!");
  return (
    <ul>
      <li>Hello</li>
      <li>world</li>
    </ul>
  )
}

class Main extends React.PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      count: 0
    }
  }

  add() {
    console.log("add按钮被单击!");
    this.setState({
      count: this.state.count + 1
    })
  }

  render() {
    console.log("Main render!");
    return (
      <div>
        <div>current:{this.state.count}</div>
        <button onClick={() => this.add()}>add one</button>
        <List/>
        <Footer/>
      </div>
    )
  }
}

export default Main;

运行之后,页面如图所示:

08f0ed26fa223b696e286c888a065f88.png

页面初次渲染,打印了如上图的内容,这很正常 -- 每个组件都得被render一次。

但当我们点击Main组件中的add按钮时(如下图),三个组件被重新render了!但是Footer组件list组件的render是毫无必要的。

bef1fe671660c97fa4c207804fc7fa05.png

使用PureComponent

设想一下,假如我们能够在List和Footer组件被渲染之前对比一下前后的props是否改变 、state是否改变,再决定是否渲染不就可以了吗?我们可以使用shouldComponentUpdate这个生命周期函数来实现,它返回一个布尔值,来定义是否render,下面是官方文档的截图:

2cf5b9093cbf4a71de60a2cc5c7c4572.png

但是如果我们每个文件都写一遍,那么实在太麻烦了,所以我们可以使用PureComponent,下面我们尝试修改上面的Footer组件。

class Footer extends React.PureComponent {
  render() {
    console.log("Footer component render!");
    return (
      <div>Footer组件</div>
    )
  }
}

从下图中可以看出,Footer组件没有被重新渲染,美中不足的是,List组件(它是一个函数式组件)仍然发生了渲染,我们下面会解决它。

b2836906ff3edb8a183715e688bf1b45.png

PureComponent原理

根据上面的描述,我们可以猜出PureComponent的原理无非就是比较前后props、state是否改变,我们先看看PureComponent

c2b4f0e3b1648f4f04d5c1105eb3172a.png

注意最后设置isPureReactComponenttrue,React通过调用checkShouldComponentUpdate来判断,这个函数位于packages/react-reconciler/src/ReactFiberClassComponent.js下,注意下面的两个红框:

  • 第一部分:判断开发者是否使用了shouldComponentUpdate,如果是,执行并返回结果。(ps.出现的startPhaseTimer貌似是一个计时功能,我们这里不做探讨)
  • 第二部分:如果这个组件是PureComponent,执行第二个红框的代码,也是核心部分了 -- 它通过调用shallowEqual比较stateprops来决定是否需要更新。

e044486bf07f5f671b4225c1918c8d72.png

来看看shallowEqual,它位于packages/shared/shallowEqual.js,下面以注释的形式给出解析:

function shallowEqual(objA: mixed, objB: mixed): boolean {
  // 面向基本数据类型的比较,下面会单独提
  if (is(objA, objB)) {
    return true;
  }

  // object 和 null 的情况,也返回false
  if (
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null
  ) {
    return false;
  }

  // 拿出所有的keys
  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);

  // 先比较长度,长度不等直接返回false
  if (keysA.length !== keysB.length) {
    return false;
  }

  // 循环遍历比较
  for (let i = 0; i < keysA.length; i++) {
    if (
      // 判断为true的条件:
      /
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值