性能優(yōu)化的學(xué)習(xí)
React Component的性能考慮
1 createClass 和 extends React.component
es5的寫法 。。。es6的寫法。沒有絕對(duì)的性能好壞之分,只不過createClass支持定義PureRenderMixin,這種寫法官方已經(jīng)不再推薦,而是建議使用PureComponent。
2 Component 和 PureComponent
shouldComponentUpdate(nextProps,nextState){ if(this.state.disenter !== nextState.disenter){ return true } return false; }
shouldComponentUpdate通過判斷 state.disenter是否發(fā)生變化來決定需不需要重新渲染組件,當(dāng)然在組件中加上這種簡單判斷,顯得有些多余和樣板化,于是React就提供了PureComponent來自動(dòng)幫我們做這件事。這樣就不需要手動(dòng)來寫shouldComponentUpdate了。
class CounterButton extends React.PureComponent {
constructor(props) {
super(props); this.state = {count: 1}; }
render() {
return (
<button color={this.props.color} onClick={() => this.setState(state => ({count: state.count + 1}))}> Count: {this.state.count} </button>
); } }
大多數(shù)請(qǐng)客下,我們使用PureComponent能夠簡化代碼,并且提高性能,但是PureComponent的自動(dòng)為我們添加的shouldComponentUpdate,只是對(duì)props和state進(jìn)行淺比較。
當(dāng)props或者state本身是嵌套對(duì)象或者數(shù)組等時(shí),淺比較并不能得到預(yù)期的結(jié)果。這會(huì)導(dǎo)致實(shí)際 的props和state發(fā)生了變化,但組件卻沒有更新的問題。
例如:
class WordAdder extends React.Component {
constructor(props) {
super(props);
this.state = {
words: ['marklar']
}; this.handleClick = this.handleClick.bind(this); }
handleClick() {
// 這個(gè)地方導(dǎo)致了bug
const words = this.state.words;
words.push('marklar');
this.setState({words: words}); }
這種情況下,PureComponent只會(huì)對(duì)this.props.words進(jìn)行一次淺比較,雖然數(shù)組里面新增了元素,但是this.props.words與nextProps.words指向的仍是同一個(gè)數(shù)組,因此this.props.words !== nextProps.words 返回的便是flase,從而導(dǎo)致ListOfWords組件沒有重新渲染,筆者之前就因?yàn)閷?duì)此不太了解,而隨意使用PureComponent,導(dǎo)致state發(fā)生變化,而視圖就是不更新,調(diào)了好久找不到原因。
最簡單避免上述情況的方式,就是避免使用可變對(duì)象作為props和state,取而代之的是每次返回一個(gè)全新的對(duì)象,如下通過concat來返回新的數(shù)組:
handleClick(){
this.setState(prevState=>({
disenter:prevState.disenter.concat(['nothing'])
}))}
可以考慮使用immutable.js來創(chuàng)建不可變對(duì)象,通過它來簡化對(duì)象比較,提高性能,這里還要提到的一點(diǎn)是雖然這里使用Pure這個(gè)詞,但是PureComponent并不是純的,因?yàn)閷?duì)于純的函數(shù)或組件應(yīng)該是沒有內(nèi)部狀態(tài),對(duì)于stateless component更符合純的定義。
3 Component 和 Stateless Functional component
createClass Component PureComponent都是通過創(chuàng)建包含狀態(tài)和用戶交互的復(fù)雜組件,當(dāng)組件本身只是用來展示,所有數(shù)據(jù)都是通過props傳入的時(shí)候,我們可以使用Stateless Functional component來快速創(chuàng)建組件,
const DAY =({
min,
second,
})=>{
return(
<View>
<Text>{min}:{second}</Text>
</View>
)
}
這種組件,沒有自身的狀態(tài),相同的props輸入,必然會(huì)獲得完全相同的組件展示,因?yàn)椴恍枰P(guān)心組件的一些生命周期函數(shù)和渲染的鉤子。讓代碼顯得更加簡潔。
總結(jié):在平時(shí)的開發(fā)的時(shí)候,多考慮React的生命周期
eg:
class LifeCycle extends React.Component {
constructor(props) { super(props); alert("Initial render"); alert("constructor"); this.state = {str: "hello"}; }
componentWillMount() {
alert("componentWillMount");
}
componentDidMount() {
alert("componentDidMount");
}
componentWillReceiveProps(nextProps) {
alert("componentWillReceiveProps");
}
shouldComponentUpdate() {
alert("shouldComponentUpdate");
return true; // 記得要返回true
}
componentWillUpdate() {
alert("componentWillUpdate");
}
componentDidUpdate() {
alert("componentDidUpdate");
}
componentWillUnmount() {
alert("componentWillUnmount");
}
setTheState() {
let s = "hello";
if (this.state.str === s) {
s = "HELLO";
}
this.setState({
str: s
});
}
forceItUpdate() {
this.forceUpdate();
}
render() {
alert("render");
return(
<div>
<span>{"Props:"}<h2>{parseInt(this.props.num)}</h2></span>
<br />
<span>{"State:"}<h2>{this.state.str}</h2></span>
</div>
);
}
}
class Container extends React.Component { constructor(props) { super(props); this.state = { num: Math.random() * 100 };
}
propsChange() {
this.setState({
num: Math.random() * 100
});
}
setLifeCycleState() {
this.refs.rLifeCycle.setTheState();
}
forceLifeCycleUpdate() {
this.refs.rLifeCycle.forceItUpdate();
}
unmountLifeCycle() {
// 這里卸載父組件也會(huì)導(dǎo)致卸載子組件
React.unmountComponentAtNode(document.getElementById("container"));
}
parentForceUpdate() {
this.forceUpdate();
}
render() {
return (
<div>
<a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.propsChange.bind(this)}>propsChange</a>
<a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.setLifeCycleState.bind(this)}>setState</a>
<a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.forceLifeCycleUpdate.bind(this)}>forceUpdate</a>
<a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.unmountLifeCycle.bind(this)}>unmount</a>
<a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.parentForceUpdate.bind(this)}>parentForceUpdateWithoutChange</a>
<LifeCycle ref="rLifeCycle" num={this.state.num}></LifeCycle>
</div>
);
}
}
ReactDom.render( <Container></Container>, document.getElementById('container') );
運(yùn)行該例子,可以發(fā)現(xiàn)生活周期的運(yùn)行順序?yàn)椋?/h5>
initial render---
constructor----
componentWillMount----
render---
componentDidMount----
render
初始狀態(tài)下,加載頁面所走的流程。
(propsChange)
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
屬性的改變。所走的生命周期
(setState)
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
這是我們?cè)谄綍r(shí)開發(fā)中,正常會(huì)使用state來更改渲染
(forceUpdate)
componentWillUpdate
render
componentDidUpdate
當(dāng)我們開發(fā)中出現(xiàn)不渲染的情況,可以使用forceUpdate。因?yàn)樵趕houldComponentUpdate正常來說,是返回為true,當(dāng)前state,和nextState,或者當(dāng)前props和nextProps的時(shí)候,會(huì)因?yàn)閟tate,props嵌套在數(shù)組或?qū)ο笾校赶蛲粋€(gè)數(shù)組或?qū)ο螅@時(shí)候,可以使用forceUpdate, 即:-->組件不走‘shouldComponentUpdate’
(unmount)
componentWillUnmount
卸載。通常有定時(shí)器或者監(jiān)聽的時(shí)候需要在此方法內(nèi)卸載。
(parentForceUpdateWithoutChange)
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate