react性能优化达到最大化的方法 immutable.js使用的必要性


Posted in Javascript onMarch 09, 2017

一行代码胜过千言万语。这篇文章呢,主要讲述我一步一步优化react性能的过程,为什么要用immutable.js呢。毫不夸张的说。有了immutable.js(当然也有其他实现库)。。才能将react的性能发挥到极致!要是各位看官用过一段时间的react,而没有用immutable那么本文非常适合你。那么我开始吧!

1、对于react的来说,如果父组件有多个子组件

想象一下这种场景,一个父组件下面一大堆子组件。然后呢,这个父组件re-render。是不是下面的子组件都得跟着re-render。可是很多子组件里面是冤枉的啊!很多子组件的props 和 state 然而并没有改变啊!!虽然virtual dom 的diff 算法很快,但是性能也不是这么浪费的啊!下面我们上代码

1).原始代码如下

以下是父组件代码。。负责输入name 和 age 然后循环显示name 和 age

export default class extends Component {
  constructor(props){
  super(props)
  this.state={
   name:"",
   age :"",
   persons:[]
  }
  }
  render() {
  const {name,age,persons} = this.state
  return (
   <div>
   <span>姓名:</span><input value={name} name="name" onChange={this._handleChange.bind(this)}></input>
   <span>年龄:</span><input value={age} name="age" onChange={this._handleChange.bind(this)}></input>
   <input type="button" onClick={this._handleClick.bind(this)} value="确认"></input>
   {persons.map((person,index)=>(
    <Person key={index} name={person.name} age={person.age}></Person>
   ))}
   </div>
  )
  }
  _handleChange(event){
  this.setState({[event.target.name]:event.target.value})
  }
  _handleClick(){
  const {name,age} = this.state
  this.setState({
   name:"",
   age :"",
   persons:this.state.persons.concat([{name:name,age:age}])
  })
 
  }
 }

以下是子组件代码单纯的显示name和age而已

class Person extends Component {
 componentWillReceiveProps(newProps){
 console.log(`我新的props的name是${newProps.name},age是${newProps.age}。我以前的props的name是${this.props.name},age是${this.props.age}是我要re-render了`);
 }
 render() {
 const {name,age} = this.props;

  return (
  <div>
   <span>姓名:</span>
   <span>{name}</span>
   <span> age:</span>
   <span>{age}</span>
  </div>
  )
 }
}

运行起来长下图这个样

react性能优化达到最大化的方法 immutable.js使用的必要性

好那么问题来了,我们看一下控制台:

react性能优化达到最大化的方法 immutable.js使用的必要性

天哪,这么多次re-reder..细细观看,不难发现。要re-render这么多次,父组件一re-render,子组件就跟着re-render啊。那么多么浪费性能,好PureRenderMixin出场

2).PureRenderMixin

因为咱用的是es2015的 Component,所以已经不支持mixin了,不过没关系,可以用HOCs,这个比mixin还更受推崇呢。我有空回用代码来展示他俩的异同,鉴于不是本文重点,,大家可以看这两篇文章了解下React Mixin 的前世今生 和Mixins Are Dead. Long Live Composition

所以在这里我们用Pure render decorator代替PureRenderMixin,那么代码如下

import pureRender from "pure-render-decorator"
...

@pureRender
class Person extends Component {
 render() {
 console.log("我re-render了");
 const {name,age} = this.props;

  return (
  <div>
   <span>姓名:</span>
   <span>{name}</span>
   <span> age:</span>
   <span>{age}</span>
  </div>
  )
 }
}

加个这东西就完事了?看上去咋这么不令人信服啊。不管怎样,试试吧。

react性能优化达到最大化的方法 immutable.js使用的必要性

果然可以做到pure render,在必须render 的时候才render。

好我们看看它的神奇之处

@pureRender

是es7的Decorators语法。上面这么写就和下面这么写一样

class PersonOrigin extends Component {
 render() {
 console.log("我re-render了");
 const {name,age} = this.props;

  return (
  <div>
   <span>姓名:</span>
   <span>{name}</span>
   <span> age:</span>
   <span>{age}</span>
  </div>
  )
 }
}
const Person = pureRender(PersonOrigin)

pureRender其实就是一个函数,接受一个Component。把这个Component搞一搞,返回一个Component看他pureRender的源代码就一目了然

function shouldComponentUpdate(nextProps, nextState) {
 return shallowCompare(this, nextProps, nextState);
}

function pureRende(component) {
 component.prototype.shouldComponentUpdate = shouldComponentUpdate;
}
module.exports = pureRender;

pureRender很简单,就是把传进来的component的shouldComponentUpdate给重写掉了,原来的shouldComponentUpdate,无论怎样都是return ture,现在不了,我要用shallowCompare比一比,shallowCompare代码及其简单,如下

function shallowCompare(instance, nextProps, nextState) {
 return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState);
}

一目了然。分别拿现在props&state和要传进来的props&state,用shallowEqual比一比,要是props&state都一样的话,就return false,是不是感觉很完美?不。。这才刚刚开始,问题就出在shallowEqual上了

3).shallowEqual的问题

shallowEqual引起的bug
很多时候,父组件向子组件传props的时候,可能会传一个复杂类型,比如我们改下。

render() {
 const {name,age,persons} = this.state
 return (
  <div>
...省略.....
  {persons.map((person,index)=>(
   <Person key={index} detail={person}></Person>
  ))}
  </div>
 )
 }

person是一个复杂类型。这就埋下了隐患,在演示隐患前,我们先说说shallowEqual,是个什么东西,shallowEqual其实只比较props的第一层子属性是不是相同,就像上述代码,props 是如下

{
 detail:{
  name:"123",
  age:"123"}
}

他只会比较props.detail ===nextProps.detail
那么问题来了,上代码
如果我想修改detail的时候考虑两种情况

情况一,我修改detail的内容,而不改detail的引用

这样就会引起一个bug,比如我修改detail.name,因为detail的引用没有改,所以props.detail ===nextProps.detail 还是为true。
所以我们为了安全起见必须修改detail的引用,(redux的reducer就是这么做的)

情况二,我修改detail的引用

这种虽然没有bug,但是容易误杀,比如如果我新旧两个detail的内容是一样的,岂不是还要,render。所以还是不完美,你可能会说用深比较就好了,但是 深比较及其消耗性能,要用递归保证每个子元素一样。

这只是说没有用immutable引起各种、、、下一篇我讲写,如何用immutable.j。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
多个iframe自动调整大小的问题
Sep 18 Javascript
js获取会话框prompt的返回值的方法
Jan 10 Javascript
js点击列表文字对应该行显示背景颜色的实现代码
Aug 05 Javascript
JS实现状态栏跑马灯文字效果代码
Oct 24 Javascript
微信小程序 wx.request(OBJECT)发起请求详解
Oct 13 Javascript
js 能实现监听F5页面刷新子iframe 而父页面不刷新的方法
Nov 09 Javascript
jquery基于layui实现二级联动下拉选择(省份城市选择)
Jun 20 jQuery
使用Vue-cli 3.0搭建Vue项目的方法
Jun 07 Javascript
vue 项目打包通过命令修改 vue-router 模式 修改 API 接口前缀
Jun 13 Javascript
使用Vue实现调用接口加载页面初始数据
Oct 28 Javascript
javascript实现计算器功能
Mar 30 Javascript
浅谈JavaScript浅拷贝和深拷贝
Nov 07 Javascript
微信小程序遇到修改数据后页面不渲染的问题解决
Mar 09 #Javascript
js实现时间轴自动排列效果
Mar 09 #Javascript
jQuery插件HighCharts绘制2D柱状图、折线图和饼图的组合图效果示例【附demo源码下载】
Mar 09 #Javascript
100行代码理解和分析vue2.0响应式架构
Mar 09 #Javascript
js实现悬浮窗效果(支持拖动)
Mar 09 #Javascript
详解vuelidate 对于vueJs2.0的验证解决方案
Mar 09 #Javascript
Bootstrap禁用响应式布局的实现方法
Mar 09 #Javascript
You might like
咖啡产品发展的三大浪潮
2021/03/04 咖啡文化
基于PHPExcel的常用方法总结
2013/06/13 PHP
php实现利用phpexcel导出数据
2013/08/24 PHP
PHP中VC6、VC9、TS、NTS版本的区别与用法详解
2013/10/26 PHP
php数组操作之键名比较与差集、交集赋值的方法
2014/11/10 PHP
php防止sql注入简单分析
2015/03/18 PHP
jQuery教程 $()包装函数来实现数组元素分页效果
2013/08/13 Javascript
JavaScript获取XML数据附示例截图
2014/03/05 Javascript
Bootstrap select多选下拉框实现代码
2016/12/23 Javascript
js禁止浏览器页面后退功能的实例(推荐)
2017/09/01 Javascript
浅谈Vue初学之props的驼峰命名
2018/07/19 Javascript
基于Vue组件化的日期联动选择器功能的实现代码
2018/11/30 Javascript
详解一个基于套接字实现长连接的express
2019/03/28 Javascript
vue+elementUi图片上传组件使用详解
2019/08/20 Javascript
Javascript中的this,bind和that使用实例
2019/12/05 Javascript
node.js中process进程的概念和child_process子进程模块的使用方法示例
2020/02/11 Javascript
Vue项目打包部署到apache服务器的方法步骤
2021/02/01 Vue.js
[05:42]DOTA2英雄梦之声_第10期_蝙蝠骑士
2014/06/21 DOTA
python读取Android permission文件
2013/11/01 Python
python标准算法实现数组全排列的方法
2015/03/17 Python
Python中的默认参数实例分析
2018/01/29 Python
python 字典修改键(key)的几种方法
2018/08/10 Python
python+mysql实现教务管理系统
2019/02/20 Python
Python逐行读取文件中内容的简单方法
2019/02/26 Python
python 类的继承 实例方法.静态方法.类方法的代码解析
2019/08/23 Python
百联网上商城:i百联
2017/01/28 全球购物
80年代复古T恤:TruffleShuffle
2018/07/02 全球购物
《胡杨》教学反思
2014/02/16 职场文书
纪念九一八事变演讲稿:牢记历史,捍卫主权
2014/09/14 职场文书
见习报告的格式
2014/10/31 职场文书
张思德观后感
2015/06/09 职场文书
我的兄弟姐妹观后感
2015/06/15 职场文书
python 用递归实现通用爬虫解析器
2021/04/16 Python
matplotlib如何设置坐标轴刻度的个数及标签的方法总结
2021/06/11 Python
三种方式清除vue路由跳转router-link的历史记录
2022/04/10 Vue.js
微信小程序APP的生命周期及页面的生命周期
2022/04/19 Javascript