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,而是采用了MutableMobx,看见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. Vue(十四)过渡(动画)

    过渡(动画) 1. 简介 Vue 在插入.更新或者移除 DOM 时,提供多种不同方式的应用过渡效果 本质上还是使用CSS3动画:transition.animation 2. 基本用法 使用trans ...

  2. JAVA自学笔记12

    JAVA自学笔记12 1.Scanner 1)JDK5后用于获取用户的键盘输入 2)构造方法:public Scanner(InputStream source) 3)System.in 标准的输入流 ...

  3. Android Studio 安装与设置

    http://www.cnblogs.com/abao0/p/6934127.html

  4. 处理程序“AllowAccessJavaScripts”在其模块列表中有一个错误模块“ManagedPipelineHandler”

    处理程序“AllowAccessJavaScripts”在其模块列表中有一个错误模块“ManagedPipelineHandler” 执行命令"cd C:\Windows\Microsoft ...

  5. OUTLOOK - Unable to Delete Meetings

    Error Information: Resolved: Check Meeting room permission.Get-MailboxFolderPermission MeetingRoom_1 ...

  6. Python内置的urllib模块不支持https协议的解决办法

    Django站点使用django_cas接入SSO(单点登录系统),配置完成后登录,抛出“urlopen error unknown url type: https”异常.寻根朔源发现是python内 ...

  7. 【php】php5.0以上,instanceof 用法

    1.instanceof php官网:http://php.net/manual/zh/language.operators.type.php 2.instanceof 用于确定一个 PHP 变量是否 ...

  8. Android 异常 android.os.NetworkOnMainThreadException

    近期在实现一个Android下的数据採集的SDK,收集用户使用数据使用HTTP发送到云平台.进行数据分析.但在发送数据时报例如以下错误: Caused by: android.os.NetworkOn ...

  9. Xshell设置密钥登录CentOS6.5_64位(文字命令版)

    1.新建/root/.ssh目录 mkdir /root/.ssh 2.创建authorized_keys文件 vi /root/.ssh/authorized_keys 3.复制公钥内容保存 :wq ...

  10. 【转载】linux系统时间自动同步:ntp

    NTP基本介绍 NTP(Network TimeProtocol,网络时间协议),使用来使本地机器与服务端机器时间保持同步的一种协议.如果我们只有一台机器那么只需要安装NTP客户端ntpdate这个包 ...