react與mox-react的shouldComponentUpdate 理解

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;
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進行處理。

相關文章
相關標籤/搜索