react性能優化中,提到的就是經過 React.PureComponent 替換 React.Component 組件進行編程。react
兩個組件之間的不一樣主要就是PureComponent作了shouldComponentUpdate的優化。對props和state進行了第一層的值===比較, 而且對 context 的變化不進行判斷。編程
經過查看React能夠看到性能優化
1 /** 2 * Copyright (c) 2013-present, Facebook, Inc. 3 * All rights reserved. 4 * 5 * This source code is licensed under the BSD-style license found in the 6 * LICENSE file in the root directory of this source tree. An additional grant 7 * of patent rights can be found in the PATENTS file in the same directory. 8 * 9 * @typechecks 10 * 11 */ 12 13 /*eslint-disable no-self-compare */ 14 15 'use strict'; 16 17 var hasOwnProperty = Object.prototype.hasOwnProperty; 18 19 /** 20 * inlined Object.is polyfill to avoid requiring consumers ship their own 21 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 22 */ 23 function is(x, y) { 24 // SameValue algorithm 25 if (x === y) { 26 // Steps 1-5, 7-10 27 // Steps 6.b-6.e: +0 != -0 28 // Added the nonzero y check to make Flow happy, but it is redundant 29 return x !== 0 || y !== 0 || 1 / x === 1 / y; 30 } else { 31 // Step 6.a: NaN == NaN 32 return x !== x && y !== y; 33 } 34 } 35 36 /** 37 * Performs equality by iterating through keys on an object and returning false 38 * when any key has values which are not strictly equal between the arguments. 39 * Returns true when the values of all keys are strictly equal. 40 */ 41 function shallowEqual(objA, objB) { 42 if (is(objA, objB)) { 43 return true; 44 } 45 46 if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { 47 return false; 48 } 49 50 var keysA = Object.keys(objA); 51 var keysB = Object.keys(objB); 52 53 if (keysA.length !== keysB.length) { 54 return false; 55 } 56 57 // Test for A's keys different from B. 58 for (var i = 0; i < keysA.length; i++) { 59 if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { 60 return false; 61 } 62 } 63 64 return true; 65 } 66 67 module.exports = shallowEqual;
項目準備升級 React16,控制檯出現了錯誤 shouldComponentUpdate should not be used when extending React.PureComponent.app
一開始看很莫名其妙,明明組件沒有本身寫shouldComponentUpdate,怎麼就報錯了。ide
後來谷歌了下,原來是項目使用了mobx進行的狀態管理。使用mox-react,對全部組件都經過 @observer 裝飾器,之前也看過mobx-react源碼,裏面的確mixin了shouldComponentUpdate方法,優化了組件的性能性能
看下面的源代碼測試
1 function mixinLifecycleEvents(target) { 2 patch(target, "componentWillMount", true) 3 ;["componentDidMount", "componentWillUnmount", "componentDidUpdate"].forEach(function ( 4 funcName 5 ) { 6 patch(target, funcName) 7 }) 8 if (!target.shouldComponentUpdate) { 9 target.shouldComponentUpdate = reactiveMixin.shouldComponentUpdate 10 } 11 } 12 { 13 shouldComponentUpdate: function(nextProps, nextState) { 14 if (isUsingStaticRendering) { 15 console.warn( 16 "[mobx-react] It seems that a re-rendering of a React component is triggered while in static (server-side) mode. Please make sure components are rendered only once server-side." 17 ) 18 } 19 // update on any state changes (as is the default) 20 if (this.state !== nextState) { 21 return true 22 } 23 // update if props are shallowly not equal, inspired by PureRenderMixin 24 // we could return just 'false' here, and avoid the `skipRender` checks etc 25 // however, it is nicer if lifecycle events are triggered like usually, 26 // so we return true here if props are shallowly modified. 27 return isObjectShallowModified(this.props, nextProps) 28 } 29 } 30 function isObjectShallowModified(prev, next) { 31 if (null == prev || null == next || typeof prev !== "object" || typeof next !== "object") { 32 return prev !== next 33 } 34 const keys = Object.keys(prev) 35 if (keys.length !== Object.keys(next).length) { 36 return true 37 } 38 let key 39 for (let i = keys.length - 1; i >= 0, (key = keys[i]); i--) { 40 if (next[key] !== prev[key]) { 41 return true 42 } 43 } 44 return false 45 }
通過測試,使用setState後,shouldComponentUpdate 的確 this.state!==nextState,可是對於this.props, nextProps的判斷,仍是存在一些差異的。優化
能夠試下下面的比較 ui
console.log(isObjectShallowModified(NaN, NaN), !shallowEqual(NaN, NaN));this
var a = {a: 1}, b = {b: 1, __proto__: {a: 1}};
console.log(isObjectShallowModified(a, b), !shallowEqual(a, b));
對於一些比較簡單的對象比較結果仍是相同的,因此對於@observer的組件就改成了React.Component進行處理。