React 性能调优总结

首先要说一个库: why-did-you-update, 地址:why-did-you-update, 利用这个库可以在页面上快速看到多余渲染的问题:

因为多数情况下我们在React组件当中是不会去写shouldComponentUpdate这个hook来避免多余渲染的,所以就造成了少量的性能浪费。虽然优化是个漫长的道路,过早优化是邪恶的,但做还是要去做的。

下面讲一下基本的一些手段

shouldComponentUpdate

在React当中,每一次的setState操作,都会让Virtual DOM去做diff操作,虽然虚拟DOM的计算很快,但是随着组件越来越多,结构越来越复杂,当你改变某个简单的state时,就会造成连带很多Component的重新render,所以我们可以在组件内部去添加shouldComponentUpdate钩子来告诉React是否要更新组件

PureComponent

当然我们在实际开发过程当中,由于数据的复杂程度来说,基本是不会去写shouldComponentUpdatehook,这时就可以去使用PureComponent类来声明组件。

PureComponent的前身是PureRenderMixin,和Component的区别就在于组件在render之前会自动执行一次shallowEqual(浅比较),就相当于组件的第一层props和state的数据如果没有发生改变,render就不会去执行,从而减少了不必要的渲染。

根据React源码,如果组件是纯组件(Pure Component),那么一下比较是很容易理解的:

if (this._compositeType === CompositeTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState);
}

为什么说是浅比较呢?这个很好理解,js的引用数据类型就很好的说明了这一点:

{} === {} //false
[] === [] //false

当然,你也可以在shouldComponentUpdate中自己来写深比较,在数据结构相对简单的情况下:

shouldComponentUpdate(nextProps, nextState) {
return nextProps.user.id === props.user.id;
}

如果是在PureComponent当中写了这个钩子,那么它就会被优先执行。

当然,在数据结构和嵌套比较深的情况下,这个方案也就不太管用了,所以,我们在前期定义数据结构时也是一个很重要的环节,可以去避免不必要的渲染。

Immutable or Immer

Facebook在2014年就推出了这个库: Immutable.js,用来使数据持久化。在数据创建后,就不得去改变,任何的增删改操作都是true一个新的Immutable对象:

import { Map } from "immutable";
const map1 = Map({ a: { aa: 1 }, b: 2, c: 3 });
const map2 = map1.set('b', 50);
map1 !== map2; // true
map1.get('b'); // 2
map2.get('b'); // 50
map1.get('a') === map2.get('a'); // true

ImmutableJS 最大的两个特性就是: immutable data structures(持久性数据结构)与 structural sharing(结构共享),持久性数据结构保证数据一旦创建就不能修改,使用旧数据创建新数据时,旧数据也不会改变,不会像原生 js 那样新数据的操作会影响旧数据。而结构共享是指没有改变的数据共用一个引用,这样既减少了深拷贝的性能消耗,也减少了内存。比如下图:

ImmutableJS的API过于复杂,而且我也没有用redux,而是采用了Mutable的Mobx,看见Mobx的作者写了一个库Immer,相对于ImmutableJS 比较简单:

import produce from "immer"
/** * Classic React.setState with a deep merge */
onBirthDayClick1 = () => {
this.setState(prevState => ({
user: {
...prevState.user,
age: prevState.user.age + 1
}
}))
} /** * ...But, since setState accepts functions, * we can just create a curried producer and further simplify! */
onBirthDayClick2 = () => {
this.setState(
produce(draft => {
draft.user.age += 1
})
)
}

代码上的优化

少用bind

每次bind都会返回一个新函数,重复创建静态函数会浪费性能。最好直接使用箭头函数绑定或者利用闭包直接把处理函数传入子组件

setState优化

在我们去setState时,最好用新值去覆盖旧值,而不是修改原值。 对于数组,我们采用es6的spread语法:

this.setState(prevState => ({
words: [...prevState.words, 'marklar'],
}));

对于对象,我们采用Object.assign或spread:

    this.setState({
a: Object.assign({}, this.state.a, {b: '2222'})
})
//或者
this.setState({
a: {...this.state.a, {b: '222'}}
})

不要在PureComponent组件的props使用直接赋值的方式

style={ { width: '100px' } } 这样的做法传入组件会造成重复渲染

这样的方式会使shallowEqual一定返回false

正确的方式:

const YourStyle = { width: '100px' } 

return (
<YourComponent style={YourStyle}></YourComponent>
)

或者我们直接就用上面说到的Immutable.js 或者 Immer.js 来处理

React 性能调优总结的更多相关文章

  1. React 性能调优原理

    一.React影响性能的两个地方 二.调优原理

  2. React 性能调优记录(下篇),如何写高性能的代码

    react性能非常重要,性能优化可以说是衡量一个react程序员水平的重要标准. 减少你的渲染 这个大家都明白,只要是父组件中用了子组件,子组件就算没用prop也会进行依次渲染, 可以用pureCom ...

  3. React如何性能调优

    一. 二.调优例子 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset=&q ...

  4. 小程序组件化框架 WePY 在性能调优上做出的探究

    作者:龚澄 导语 性能调优是一个亘古不变的话题,无论是在传统H5上还是小程序中.因为实现机制不同,可能导致传统H5中的某些优化方式在小程序上并不适用.因此必须另开辟蹊径找出适合小程序的调估方式. 本文 ...

  5. web前端性能调优

    最近2个月一直在做手机端和电视端开发,开发的过程遇到过各种坑.弄到快元旦了,终于把上线了.2个月干下来满满的的辛苦,没有那么忙了自己准备把前端的性能调优总结以下,以方便以后自己再次使用到的时候得于得心 ...

  6. [网站性能2]Asp.net平台下网站性能调优的实战方案

    文章来源:http://www.cnblogs.com/dingjie08/archive/2009/11/10/1599929.html 前言    最近帮朋友运营的平台进行了性能调优,效果还不错, ...

  7. Asp.net平台下网站性能调优的实战方案(转)

    转载地址:http://www.cnblogs.com/chenkai/archive/2009/11/07/1597795.html 前言 最近帮朋友运营的平台进行了性能调优,效果还不错,所以写出来 ...

  8. 第0/24周 SQL Server 性能调优培训引言

    大家好,这是我在博客园写的第一篇博文,之所以要开这个博客,是我对MS SQL技术学习的一个兴趣记录. 作为计算机专业毕业的人,自己对技术的掌握总是觉得很肤浅,博而不专,到现在我才发现自己的兴趣所在,于 ...

  9. sqlserver性能调优第一步

    相信不少的朋友,无论是做开发.架构的,还是DBA等,都经常听说“调优”这个词.说起“调优”,可能会让很多技术人员心头激情澎湃,也可能会让很多人感觉苦恼,不知道如何入手.当然,也有很多人对此不屑一顾,因 ...

随机推荐

  1. elastic-job详解(二):作业的调度

    JobScheduler是elastic-job作业调度的关键类,也是起始类,在包com.dangdang.ddframe.job.lite.api下.调度任务的执行需要包含两大步骤:任务的配置和任务 ...

  2. antv g6

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  3. 如何确定Isilon cluster的网卡类型是40GbE的还是10GbE的

    可以使用isi upgrade cluster firmware devices命令. 从命令行输出可以看到,当前的cluster使用的是40G的前端网卡. 如果是10G网卡,输出结果应当是如下的样子 ...

  4. NLP第9章 NLP 中用到的机器学习算法——基于统计学(文本分类和文本聚类)

  5. srs2.0安装问题

    原文: https://blog.csdn.net/ddr77/article/details/52511340 编译配置如下 ./configure --disable-all --with-ssl ...

  6. AWStats日志分析系统

    1.什么是AWStats AWStats是一款功能强大且功能强大的免费工具,可以图形方式生成高级Web,流媒体,ftp或邮件服务器统计信息.此日志分析器用作CGI或命令行, 并在几个图形网页中显示您的 ...

  7. 设计模式之二十一:中介者模式(Mediator)

    中介者模式:定义了一个对象.用来封装一系列对象的交互.中介者模式通过使对象之间不必显式引用减少了对象之间的耦合,而且同意你独立改变它们之间的交互. 中介者模式就是将对象之间的交互封装在了一个独立的对象 ...

  8. 关于docker 意外停止,重新快速启动措施

    1. 我们要重启这个镜像,需要知道这个镜像ID,类似这个: 7079ff99e10ac326726a364348853c0e508cad8ce00ae970f3c800f172a40252 那么你可以 ...

  9. 【Linux】CentOs的常用命令

    1.文件目录操作命令            ls:列出当前路径下的文件或者目录列表                -l 列出详细信息                -a 列出所有的文件信息,包括隐藏文 ...

  10. redis应用-sortedset实现排行榜(转载)

    package site.zy9.redisApp.test; import java.util.HashMap; import java.util.List; import java.util.Ma ...