React性能优化总结
初学者对React可能满怀期待,觉得React可能完爆其它一切框架,甚至不切实际地认为React可能连原生的渲染都能完爆——对框架的狂热确实会出现这样的不切实际的期待。让我们来看看React的官方是怎么说的。React官方文档在Advanced Performanec这一节,这样写道:
显然React自己也其实只是想尽量达到跟非React版本相当的性能。 你所不知道的renderreact的组件渲染分为初始化渲染和更新渲染。
但是当我们要更新某个子组件的时候,如下图的绿色组件(从根组件传递下来应用在绿色组件上的数据发生改变):
我们的理想状态是只调用关键路径上组件的render,如下图:
但是react的默认做法是
更新阶段的生命周期
shouldComponentUpdatereact在每个组件生命周期更新的时候都会调用一个shouldComponentUpdate(nextProps,nextState)函数。它的职责就是返回true或false,true表示需要更新,false表示不需要, 为了进一步说明问题,我们再引用一张官网的图来解释,如下图( SCU表示shouldComponentUpdate,绿色表示返回true(需要更新),红色表示返回false(不需要更新);vDOMEq表示虚拟DOM比对,绿色表示一致(不需要更新),红色表示发生改变(需要更新)):
根据渲染流程,首先会判断shouldComponentUpdate(SCU)是否需要更新。如果需要更新,则调用组件的render生成新的虚拟DOM,然后再与旧的虚拟DOM对比(vDOMEq),如果对比一致就不更新,如果对比不同,则根据最小粒度改变去更新DOM;如果SCU不需要更新,则直接保持不变,同时其子元素也保持不变。
带坑的写法:
性能检测工具React官方提供的:React.addons.Perfreact官方提供一个插件 或者输入Perf.printWasted()查看下不需要的的浪费组件render,如下图(官方图片): 优化前: 其他的检测工具react-perf-tool为React应用提供了一种可视化的性能检测方案,该工程同样是基于React.addons,但是使用图表来显示结果,更加方便。 React官方的解决方案PureRenderMixin(es5)var PureRenderMixin = require('react-addons-pure-render-mixin'); React.createClass({ mixins: [PureRenderMixin],render: function() { return <div className={this.props.className}>foo</div>; } }); Shallow Compare (es6)var shallowCompare = require('react-addons-shallow-compare'); export class SampleComponent extends React.Component { shouldComponentUpdate(nextProps,nextState) { return shallowCompare(this,nextProps,nextState); } render() { return <div className={this.props.className}>foo</div>; } } es7装饰器的写法: 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> ) } } pureRender很简单,就是把传进来的component的shouldComponentUpdate给重写掉了,原来的shouldComponentUpdate,无论怎样都是return ture,现在不了,我要用shallowCompare比一比,shallowCompare代码及其简单,如下: function shallowCompare(instance,nextState) { return !shallowEqual(instance.props,nextProps) || !shallowEqual(instance.state,nextState); } 缺点shallowEqual其实只比较props的 { detail: { name: "123",age: "123" } } 他只会比较 补充(4.25)React在 class CounterButton extends React.PureComponent { constructor(props) { super(props); this.state = {count: 1}; } render() { return ( <button color={this.props.color} onClick={() => this.setState(state => ({count: state.count + 1}))}> Count: {this.state.count} </button> ); } } 在ES6里面写起来简直爽歪歪,可以一样只支持浅比较。 immutable.js我们也可以在 Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。 Immutable 实现的原理是
Immutable 则提供了简洁高效的判断数据是否变化的方法,只需 === 和 is 比较就能知道是否需要执行 render(),而这个操作几乎 0 成本,所以可以极大提高性能。修改后的 import { is } from 'immutable'; shouldComponentUpdate: (nextProps = {},nextState = {}) => { const thisProps = this.props || {},thisState = this.state || {}; if (Object.keys(thisProps).length !== Object.keys(nextProps).length || Object.keys(thisState).length !== Object.keys(nextState).length) { return true; } for (const key in nextProps) { if (!is(thisProps[key],nextProps[key])) { return true; } } for (const key in nextState) { if (thisState[key] !== nextState[key] || !is(thisState[key],nextState[key])) { return true; } } return false; } react-immutable-render-mixin这是一个facebook/immutable-js的react pure render mixin 的库,可以简化很多写法。 import React from 'react'; import { immutableRenderDecorator } from 'react-immutable-render-mixin'; @immutableRenderDecorator class Test extends React.Component { render() { return <div></div>; } } 参考文章Immutable 详解及 React 中实践 无状态组件为了避免一定程度的浪费,react官方还在0.14版本中加入了 // es6 const HelloMessage = (props) => <div> Hello {props.name}</div>; render(<HelloMessage name="John" />,mountNode); 因为无状态组件只是函数,所以它没有实例返回,这点在想用 refs 获取无状态组件的时候要注意,参见DOM 操作。 高阶组件(接下来的方向)
参考文章使用ES6编写React应用(4):使用高阶组件替代Mixins React同构直出(接下来方向)
React在减少重复渲染方面确实是有一套独特的处理办法,那就是virtual DOM,但显示在首次渲染的时候React绝无可能超越原生的速度。因此,我们在做优化的时候,接下来可以做的事情就是:
参考文章React同构直出优化总结 参考文章react组件性能优化探索实践
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- vue目录结构熟悉
- flash图片批量上传处理专用php类
- flash-builder – 如何在Flash Builder 4.6中进行项目范围的
- 自定义组件时 Binary XML file line Error inflating class
- c# – 如何使用NHibernate加载大型复杂对象图
- c# – 如何在类库项目中使用Server.MapPath
- ruby-on-rails-3 – 为什么我的current_user帮助方法在测试
- 微信上传图片出现的问题和总结
- ruby-on-rails – 如何在Ruby on Rails的autotest中使用本机
- cocos2dx 3.3 tilemap 缩放滑动并且准确点击对象