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. python-校验密码小练习

    #校验密码是否合法的小练习#1.密码长度5到10位:#2.密码里面必须包含,大写字母,小写字母,数字#3.最多输入5次 写程序过程中遇到了两个问题,第二个循环里的P是把password的值循环传到p里 ...

  2. Linux命令之yum篇

    作业六:yum命令1) 自定义yum仓库:createrepo[root@localhost /]#mkdir /rpm_bak[root@localhost /]#cp /media/Package ...

  3. C# 发送消息SendKeys、SendMessage、keybd_event的用法

    一.C#中SendKeys的用法 功能:将一个或多个按键消息发送到活动窗口,就如同在键盘上进行输入一样. 语法: SendKeys.Send(string keys); SendKeys.SendWa ...

  4. WordPress主题开发:按分类调用文章

    调用catid为2的分类下的文章,就是后台分类链接的tag_ID <?php $cat_query = new WP_Query(array( 'cat' => '2' )); ?> ...

  5. 在python里调用java的py4j的使用方法

    py4j可以使python和java互调 py4j并不会开启jvm,需要先启动jvm server,然后再使用python的client去连接jvm GatewayServer实例:允许python程 ...

  6. UseSwagger

    if [ "$UseSwagger" != "true" ]; then sed -i "s/\"UseSwagger\": tr ...

  7. 通过Nginx反向代理之后客户端验证码session不一致造成无法验证通过的问题解决

    location / { proxy_pass http://127.0.0.1:9080/app/; proxy_cookie_path /app/ /; proxy_cookie_path /ap ...

  8. SharePoint online 获取文件版本记录

    endpoint: _api/web/GetFileByServerRelativeUrl('/allDoc/xxx.pdf')/Versions 问题: 第一次使用,无论在本地还是o365上,都只返 ...

  9. [转]tensorflow中的gather

    原文链接 tensorflow中取下标的函数包括:tf.gather , tf.gather_nd 和 tf.batch_gather. 1.tf.gather(params,indices,vali ...

  10. 分析轮子(八)- List.java 各种遍历方式及遍历时移除元素的方法

    注:玩的是JDK1.7版本 1:先尝栗子,再分析,代码简单,注释清晰,可自玩一下 /** * @description:测试集合遍历和移除元素的方式 * @author:godtrue * @crea ...