首页 > 其他分享 >React性能优化 之 不可变数据

React性能优化 之 不可变数据

时间:2022-11-07 14:00:49浏览次数:75  
标签:数据 items 性能 js React state 组件 优化

什么是不可变数据

不可变数据的概念来自函数式编程。

在函数式编程中,对已初始化的“变量”是不可以更改的,每次更改都要创建一个新的“变量”。

Javascript 在语言层没有实现不可变数据,需要借助第三方库来实现。(immutable.js 或者 immer.js)


为什么使用不可变数据?

使用不可变数据的目的是为了跟踪数据的改变。

如果直接修改数据,那么就很难跟踪到数据的改变,跟踪数据的改变需要可变对象可以与改变之前的版本进行对比,这样整个对象树都需要被遍历一次。

但跟踪不可变数据的变化相对来说就容易多了。

如果发现对象变成了一个新对象,那么我们就可以说对象发生改变了。我们可以很轻松的确定不可变数据是否发生了改变,从而确定何时对组件进行重新渲染。

当一个组件的 props 或 state 变更,React 会将最新返回的元素与之前渲染的元素进行对比,以此决定是否有必要更新真实的 DOM。

当它们不相同时,React 会更新该 DOM。

虽然 React 已经保证未变更的元素不会进行更新,但即使 React 只更新改变了的 DOM 节点,重新渲染仍然花费了一些时间。

在大部分情况下它并不是问题,不过如果它已经慢到让人注意了,你可以通过覆盖生命周期方法 shouldComponentUpdate 来进行提速。该方法会在重新渲染前被触发。

如果你知道在什么情况下你的组件不需要更新,你可以在 shouldComponentUpdate 中返回 false 来跳过整个渲染过程。其包括该组件的 render 调用以及之后的操作。


React性能优化离不开不可变值

shouldComponentUdpate中可以接收两个参数,nextProps和nextState,假如我们通过判断this.props.xxx和nextProps.xxx相等以及this.state.xxx与nextState.xxx相等,可以将返回值设置为false,说明此次并不需要更新子组件:

class CounterButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: 1};
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (this.props.color !== nextProps.color) {
      return true;
    }
    if (this.state.count !== nextState.count) {
      return true;
    }
    return false;
  }

  render() {
    return (
      <button
        color={this.props.color}
        onClick={() => this.setState(state => ({count: state.count + 1}))}>
        Count: {this.state.count}
      </button>
    );
  }
}

React v15.3新增加了一个PureComponent类,能够对props和state进行浅比较来减少render函数的执行次数,避免不必要的组件渲染,实现性能上的优化。

什么是浅比较?

答:我们知道JS中的变量类型分为基本类型(number、string、boolean、undefined、null、symbol)和引用类型(function、object、function),基本类型的值保存在栈内存当中,引用类型的值保存在堆内存当中,栈内存中只保存指向堆内存的引用。

而浅比较就是只对栈内存中的数据进行比较


下面例子使用了PureComponent,而且只改变了数组items里的值,而没改变items的引用地址,所以认为items没有发生变化,不会触发render函数,不会触发组件的渲染。

class App extends PureComponent {
  state = {
    items: [1, 2, 3]
  }
  handleClick = () => {
    const { items } = this.state;
    items.pop();
    this.setState({ items });
  }
  render() {
    return (
        <div>
            <ul>
                {this.state.items.map(i => <li key={i}>{i}</li>)}
            </ul>
            <button onClick={this.handleClick}>delete</button>
        </div>
    )
  }
}

如果想实现组件更新,可以按如下的方式,创建一个新的数组,将新数组的地址赋给items,这样子栈内存中的引用就改变了:

handleClick = () => {
    const { items } = this.state;
    items.pop();
    var newItem = [...items];
    this.setState({ item: newItem });
}

immutable.js / immer.js

PureComponent帮我们做了浅层的比较。

如果需要出现引用嵌套引用的数据结构的话,类似下述结构:

handleClick() {
  this.setState(state => ({
    objA: {
      ...state.objA,
      objB: {
        ...state.objA.objB,
        objC: {
          ...state.objA.objB.objC,
          stringA: 'string',
        }
      },
    },
  }));
};

这样子每一层都使用展开运算符,来改变栈内存中的引用地址,太过繁琐。


那为什么不使用深拷贝呢?

答:深拷贝会让所有组件都接收到新的数据,让 shouldComponentUpdate 失效。深比较每次都比较所有值,当数据层次很深且只有一个值变化时,这些比较是对性能的浪费。

视图层的代码,我们希望它更快响应,所以使用 immutable 库进行不可变数据的操作,也算是一种空间换时间的取舍。


immutable.js和immer.js的区别

immutable.js

  • 自己维护了一套数据结构,Javascript 的数据类型和 immutable.js 的类型需要相互转换,对数据有侵入性。
  • 库的体积比较大(63KB),不太适合包体积紧张的移动端。
  • API 极其丰富,学习成本较高。
  • 兼容性非常好,支持 IE 较老的版本。

immer.js

  • 使用 Proxy 实现,兼容性差。
  • 体积很小(12KB),移动端友好。
  • API 简洁,使用 Javascript 自己的数据类型,几乎没有理解成本。

学习参考:

标签:数据,items,性能,js,React,state,组件,优化
From: https://www.cnblogs.com/luckest/p/16865709.html

相关文章

  • 为什么SQL语句Where 1=1 and在SQL Server中不影响性能
       原文链接:https://www.cnblogs.com/CareySon/p/4138575.html最近一个朋友和我探讨关于Where1=1and这种形式的语句会不会影响性能。最后结论是不影响。   ......
  • .NET性能优化-是时候换个序列化协议了
    计算机单机性能一直受到摩尔定律的约束,随着移动互联网的兴趣,单机性能不足的瓶颈越来越明显,制约着整个行业的发展。不过我们虽然不能无止境的纵向扩容系统,但是我们可以分布......
  • react文档高级指引的一些总结
    1,关于纯函数的概念总结函数的目的是为了解决一些计算逻辑,通过入参传递计算所需的变量,出参导出计算结果。如果已知函数内部的处理逻辑,通过入参,就可以知道出参的结果,就可以......
  • 面试官最喜欢问的几个react相关问题
    除了在构造函数中绑定this,还有其它方式吗你可以使用属性初始值设定项(propertyinitializers)来正确绑定回调,create-react-app也是默认支持的。在回调中你可以使用箭头......
  • HashMap 的 7 种遍历方式与性能分析!
    参考来自于:HashMap的7种遍历方式与性能分析!方法之1:使用forEachpublicclassHashMapTest{publicstaticvoidmain(String[]args){//创建并赋值......
  • react react-router-dom6 mobx6整理
    reactreact-router-domv6route/index.jsimportReact,{Suspense,lazy}from'react'importLayoutfrom'../views/Layout/index'constHome=lazy(()=>......
  • 004 Web Assembly康威游戏之优化
    0介绍视频地址:https://www.bilibili.com/video/BV1eg411g7c8相关源码:https://github.com/anonymousGiga/Rust-and-Web-Assembly1说明在上一节的实现中,我们是在Rust中实现......
  • 华为云 MRS 基于 Apache Hudi 极致查询优化的探索实践
    背景湖仓一体(LakeHouse)是一种新的开放式架构,它结合了数据湖和数据仓库的最佳元素,是当下大数据领域的重要发展方向。华为云早在2020年就开始着手相关技术的预研,并落地在华......
  • React组件基础二
    1.注册事件React注册事件与DOM的事件语法非常像语法on+事件名={事件处理程序}比如onClick={this.handleClick}注意:React事件采用驼峰命名法,比如onMouseEnter,onClick......
  • SQL优化
    SQL优化昨天(2022-7-22)上线了我的一个功能,测试环境数据量较小,问题不大,但是上生产之后,直接卡死了,然后就开始了这么一次SQL优化,这里记录一下。不太方便透露公司的表结构,这里......