在react开发中,常常会遇到组件重复渲染的问题,父组件一个state的变化,就会致使以该组件的全部子组件都重写render,尽管绝大多数子组件的props没有变化vue
首先,先上一张react生命周期图:react
这张图将react的生命周期分为了三个阶段:生成期、存在期、销毁期,这样在create、props、state、unMount状态变化时咱们能够清楚的看到reacte触发了哪些生命周期钩子以及何时会render。git
若是咱们须要更改root的一个state,使绿色组件视图更改github
若是你写过vue,你会发现组件更新是如上图那样的(视图指令已编译为修改视图的函数存放在绑定的state里的属性里,因此可以作到靶向修改),而react会以组件为根,从新渲染整个组件子树,以下图(绿色是指望的render路径,橙色是无用render):数组
因此在react里,咱们探讨的render性能优化是react调用render的路径以下:性能优化
shouldComponentUpdate(nextProps, nextState)
使用shouldComponentUpdate()以让React知道当前状态或属性的改变是否不影响组件的输出,默认返回ture,返回false时不会重写render,并且该方法并不会在初始化渲染或当使用forceUpdate()时被调用,咱们要作的只是这样:数据结构
shouldComponentUpdate(nextProps, nextState) { return nextState.someData !== this.state.someData }
可是,state里的数据这么多,还有对象,还有复杂类型数据,react的理念就是拆分拆分再拆分,这么多子组件,我要每一个组件都去本身一个一个对比吗??不存在的,这么麻烦,要知道咱们的终极目标是坐享其成-_-app
React.PureComponent 与 React.Component 几乎彻底相同,但 React.PureComponent 经过props和state的浅对比来实现 shouldComponentUpate()。若是对象包含复杂的数据结构,它可能会因深层的数据不一致而产生错误的否认判断(表现为对象深层的数据已改变视图却没有更新)函数
关注点:
const hasOwnProperty = Object.prototype.hasOwnProperty; /** * inlined Object.is polyfill to avoid requiring consumers ship their own * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is */ function is(x: mixed, y: mixed): boolean { // SameValue algorithm if (x === y) { // Steps 1-5, 7-10 // Steps 6.b-6.e: +0 != -0 // Added the nonzero y check to make Flow happy, but it is redundant return x !== 0 || y !== 0 || 1 / x === 1 / y; } else { // Step 6.a: NaN == NaN return x !== x && y !== y; } } /** * Performs equality by iterating through keys on an object and returning false * when any key has values which are not strictly equal between the arguments. * Returns true when the values of all keys are strictly equal. */ function shallowEqual(objA: mixed, objB: mixed): boolean { if (is(objA, objB)) { return true; } if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { return false; } const keysA = Object.keys(objA); const keysB = Object.keys(objB); if (keysA.length !== keysB.length) { return false; } // Test for A's keys different from B. for (let i = 0; i < keysA.length; i++) { if ( !hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]]) ) { return false; } } return true; }
针对以上规则咱们在项目开发种能够作出以下优化:性能
尽可能将复杂类型数据(ArrayList)所关联的视图单独拆成PureComonent有助于提升渲染性能,好比表单、文本域和复杂列表在同一个 render() 中,表单域的输入字段改变会频繁地触发 setState() 从而致使 组件 从新 render()。而用于渲染复杂列表的数据其实并无变化,但因为从新触发 render(),列表仍是会从新渲染。
我想复杂数组没变化时也不要render(), 那你用react-immutable-render-mixin,来,咱们看看插件的介绍:
Users are urged to use PureRenderMixin with facebook/immutable-js. If performance is still an issue an examination of your usage of Immutable.js should be your first path towards a solution. This library was created from experimentations with Immutable that were ultimately erroneous; improper usage of Immutable.js 💩. Users should be able to achieve maximum performance simply using PureRenderMixin.
译:不能以正确的姿式来使用immutable-js作优化,你就不要瞎折腾了,用它react-immutable-render-mixin就好了
它和ProComponent原理同样,惟一的区别就是新旧数据的对比,react-immutable-render-mixin用了immutable-js 的is()方法去作对比,性能强,复杂类型数据也能对比(这里不对immutable-js作讨论,一篇很不错的文章Immutable 详解及 React 中实践),相比于React.PureComponent更方便---源码
import Immutable from 'immutable'; const is = Immutable.is.bind(Immutable); export default function shallowEqualImmutable(objA, objB) { if (objA === objB || is(objA, objB)) { return true; } if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { return false; } const keysA = Object.keys(objA); const keysB = Object.keys(objB); if (keysA.length !== keysB.length) { return false; } // Test for A's keys different from B. const bHasOwnProperty = Object.prototype.hasOwnProperty.bind(objB); for (let i = 0; i < keysA.length; i++) { if (!bHasOwnProperty(keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { return false; } } return true; }
用法不少,我喜欢Decorator:
import React from 'react'; import { immutableRenderDecorator } from 'react-immutable-render-mixin'; @immutableRenderDecorator class Test extends React.Component { render() { return <div></div>; } }