4. React性能优化:避免组件更新

2020-08-20  本文已影响0人  萘小蒽

首先需要了解的周期方法是ShouldComponentUpdate(nextProps,nextState),它对于构建性能关键型的应用场景尤为重要。它会在componentWillUpdate()之前触发。当非必须时可以取消组件更新。

有一类组件在render()方法中只使用了this.state、this.props,而没有其他额外的函数调用。这一类组件被称为“纯组件”。我们可以在shouldComponentUpdate()中比较前后的状态与属性,如果没有发生任何变化,返回false,以节省部分处理能力。

 var Counter = React.createClass({
        name: 'Counter',
        propTypes: {
          count: React.PropTypes.number.isRequired,
        },
        
        render: function() {
          console.log(this.name + '::render()');
          return React.DOM.span(null, this.props.count);
        }
      });

      var TextAreaCounter = React.createClass({
        name: 'TextAreaCounter',
        
        // mixins: [logMixin],

        propTypes: {
          defaultValue: React.PropTypes.string,
        },

        getInitialState: function() {
          return {
            text: this.props.defaultValue,
          };
        },

        _textChange: function(ev) {
          this.setState({
            text: ev.target.value,
          });
        },

        render: function() {
          console.log(this.name + '::render()');
          var counter = null;
          if (this.state.text.length > 0) {
            counter = React.DOM.h3(null, 
              React.createElement(Counter, {
                count: this.state.text.length,
              })
            );
          }
          return React.DOM.div(null,
            React.DOM.textarea({
              value: this.state.text,
              onChange: this._textChange,
            }),
            counter
          );
        }
      });

      var myTextAreaCounter = ReactDOM.render(
        React.createElement(TextAreaCounter, {
          defaultValue: "Bob",
        }),
        document.getElementById("app")
      );

上面这个例子中,输入框内初始化为Bob,长度为3,当你复制长度为3的字符串在输入框中时,Counter组件中的长度并没有发生变化(依然为3),但是render却触发了。

Counter组件中加入shouldComponentUpdate方法:

        shouldComponentUpdate: function(nextProps, nextState) {
          // console.log(this.name + '::shouldComponentUpdate()');
          return nextProps.count !== this.props.count;
        },

PureRebderMixin
上面的优化只需要对this.props和nextProps,以及this.state和nextState进行比较即可,对此React通过mixin的形式提供了一种通用现实,并且可以简单的应用与任何组件。

var Counter = React.createClass({
        name: 'Counter',
        mixins: [React.addons.PureRenderMixin],
        propTypes: {
          count: React.PropTypes.number.isRequired,
        },
        render: function() {
          console.log(this.name + '::render()');
          return React.DOM.span(null, this.props.count);
        }
      });

在0.14版本之后,React.addons 单独分离出来(与Babel 6类似),各自成为插件,需要单独加载。
不希望完全引入全部插件,依靠自己实现:

var ReactComponentWithPureRenderMixin = {
    shouldComponentUpdate: function(nextProps, nextState){
        return !shallowEqua(this.props,this.nextProps)||!shallowEqua(this.state,this.nextState);
    }
}

仅仅是对相等性进行浅层(非递归)检查

function shallowEqual(objA, objB) {
    if(objA === objB) {
        return true;
    }
    var keyA = Object.keys(objA),
        keyB = Object.keys(objB);

    if(keyA.length != keyB.length) {
        return false;
    }

    for(var idx = 0, len = keyA.length; idx < len; idx++ ) {
        var key = keyA[idx];
        
        if(!objB.hasOwnProperty(key)) {
            return false;
        }
        var valueA = objA[key],
              valueB = objB[key];
        // 无差别比较,引用类型比较引用,基础类型直接比较值
        if(valueA !== valueB) {
            return false;
        }
    }
    return true;
}
上一篇 下一篇

猜你喜欢

热点阅读