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;
}