最近看了程墨的幾篇文章榕栏,對setState這個API有了更加深入的認(rèn)識计螺,下面總結(jié)一下。
先回顧一下React組件的生命周期冶忱。
一尾菇、組件的生命周期
在掛載期首先會調(diào)用componentWillMount(),然后會接著觸發(fā)render()渲染到頁面囚枪,最后調(diào)用componentDidMount(),在卸載前會調(diào)用componentWillUnmont()派诬,然后卸載組件。
在組件更期時(此處指以props改變?yōu)槔?链沼,首先會從父組件傳來props默赂,觸發(fā)鉤子函數(shù)(hook)componentWillReceiveProps()(若是state改變不會觸發(fā)),然后觸發(fā)shouldComponentUpdate(),如果shouldComponentUpdate()函數(shù)返回false,這時候更新過程就被中斷了括勺,render函數(shù)也不會被調(diào)用了缆八,這時候React不會放棄掉對this.state的更新的,所以雖然不調(diào)用render疾捍,依然會更新this.state耀里。若返回的是true,就會緊接著觸發(fā)componentWillUpdate(),接著觸發(fā)render()拾氓,更新組件的渲染冯挎,最后觸發(fā)觸發(fā)componentDidUpdate(),組件卸載和上述流程一樣咙鞍。
二房官、setState()介紹
引用網(wǎng)上的說法:
React抽象來說,就是一個公式
[圖片上傳失敗...(image-cfb7ee-1531880117865)]
setState是React用來更新state的一個API续滋,用得越多翰守,發(fā)現(xiàn)setState()有很多讓人入坑的地方:
- 使用setState()一般情況下(后面會介紹特殊情況)不會立即更新state的值;
- setState通過引發(fā)一次組件的更新過程來引發(fā)重新繪制疲酌;
- 多次setState函數(shù)調(diào)用產(chǎn)生的效果會合并蜡峰。
對于第一點了袁,引用網(wǎng)上的例子:
function incrementMultiple() {
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
}
上面的函數(shù)運行時,似乎對state.count的值加了3次湿颅,但實際上只加了一次载绿,原因正是setState不會立即改變state的值所以后面兩次的this.state其實還是最初的state。
第二點需要提到上面的組件更新期的聲明周期油航,setState調(diào)用引起的React的更新生命周期函數(shù)4個函數(shù):
- shouldComponentUpdate()
- componentWillUpdate()
- render()
- componentDidUpdate()
當(dāng)shouldComponentUpdate函數(shù)被調(diào)用的時候崭庸,this.state沒有得到更新。
當(dāng)componentWillUpdate函數(shù)被調(diào)用的時候谊囚,this.state依然沒有得到更新怕享。
直到render函數(shù)被調(diào)用的時候,this.state才得到更新。
(或者,當(dāng)shouldComponentUpdate函數(shù)返回false贝润,這時候更新過程就被中斷了,render函數(shù)也不會被調(diào)用了跌帐,這時候React不會放棄掉對this.state的更新的,所以雖然不調(diào)用render芳来,依然會更新this.state含末。)
所以setState一般不會立即更新state的值猜拾,知道render()函數(shù)觸發(fā)即舌。
對于第三點可以簡單理解為:
連續(xù)調(diào)用了兩次this.setState,但是只會引發(fā)一次更新生命周期挎袜,不是兩次顽聂,因為React會將多個this.setState產(chǎn)生的修改放在一個隊列里,緩一緩盯仪,攢在一起紊搪,覺得差不多了再引發(fā)一次更新過程。這樣做的好處是全景,不用每次setState就去觸發(fā)一次render()耀石,這樣太消耗性能。
另外setState()可以接受一個函數(shù)作為參數(shù)爸黄,也就是說可以在里面參入回調(diào)函數(shù):
function increment(state, props) {
return {count: state.count + 1};
}
function incrementMultiple() {
this.setState(increment);
this.setState(increment);
this.setState(increment);
}
值得注意的是:同樣是把狀態(tài)中的count加1滞伟,但是函數(shù)increment的狀態(tài)的來源不是this.state,而是輸入?yún)?shù)state炕贵,所以加1是累加上去的梆奈。
值得一提的是,在increment函數(shù)被調(diào)用時称开,this.state并沒有被改變亩钟,依然乓梨,要等到render函數(shù)被重新執(zhí)行時(或者shouldComponentUpdate函數(shù)返回false之后)才被改變。這也就是說如果清酥, this.setState(increment)中插入 this.setState({count: this.state.count + 1})會讓前面的努力白費扶镀。如下:
function incrementMultiple() {
this.setState(increment);
this.setState(increment);
this.setState({count: this.state.count + 1});
this.setState(increment);
}
在幾個函數(shù)式setState調(diào)用中插入一個傳統(tǒng)式setState調(diào)用(嗯,我們姑且這么稱呼以前的setState使用方式)总处,最后得到的結(jié)果是讓this.state.count增加了2狈惫,而不是增加4,所以不宜混用兩種發(fā)法鹦马。