摘要:除此之外指的是繞過通過直接添加的事件處理函數(shù)和產(chǎn)生的異步調(diào)用。但是,當(dāng)在調(diào)用事件處理函數(shù)之前就會(huì)調(diào)用,這個(gè)函數(shù)會(huì)把修改為,造成的后果就是由控制的事件處理過程不會(huì)同步更新。
拋出問題
class Example extends Component { contructor () { super() this.state = { value: 0, index: 0 } } componentDidMount () { this.setState({value: this.state.value + 1}) console.log(this.state.value) // 第一次輸出 this.setState({value: this.state.value + 1}) console.log(this.state.value) // 第二次輸出 setTimeout(() => { this.setState({value: this.state.value + 1}) console.log(this.state.value) // 第三次輸出 this.setState({value: this.state.value + 1}) console.log(this.state.value) // 第四次輸出 }, 0); this.refs.button.addEventListener("click", this.click) } click = () => { this.setState({value: this.state.index + 1}) this.setState({value: this.state.index + 1}) } render () { return (value: {this.state.value}index: {this.props.index}) } }
這四次輸出,按常理來說分別是: 1,2,3,4。但是,實(shí)際輸出為: 0, 0, 2, 3
setState的注意點(diǎn)
setState不會(huì)立刻改變React組件中state的值(即setState是異步更新)
setState通過一個(gè)隊(duì)列機(jī)制實(shí)現(xiàn)state更新;
當(dāng)執(zhí)行setState時(shí),會(huì)將需要更新的state合并后放入狀態(tài)隊(duì)列,而不會(huì)立即更新,隊(duì)列可以高效的批量更新state;
通過this.state直接修改的值,state不會(huì)放入狀態(tài)隊(duì)列,當(dāng)下次調(diào)用setState并對(duì)狀態(tài)隊(duì)列進(jìn)行合并時(shí),會(huì)忽略之前直接被修改的state.
setState通過引發(fā)一次組件的更新過程來引發(fā)重新繪制
此處重繪指的就是引起React的更新生命周期函數(shù)4個(gè)函數(shù):
shouldComponentUpdate(被調(diào)用時(shí)this.state沒有更新;如果返回了false,生命周期被中斷,雖然不調(diào)用之后的函數(shù)了,但是state仍然會(huì)被更新)
componentWillUpdate(被調(diào)用時(shí)this.state沒有更新)
render(被調(diào)用時(shí)this.state得到更新)
componentDidUpdate
多個(gè)相鄰的state的修改可能會(huì)合并到一起一次執(zhí)行
this.setState({name: "Pororo"}) this.setState({age: 20})
等同于
this.setState({name: "Pororo",age: 20})
上面兩塊代碼的效果是一樣的。如果每次調(diào)用都引發(fā)一次生命周期更新,那性能就會(huì)消耗很大了。所以,React會(huì)將多個(gè)this.setState產(chǎn)生的修改放進(jìn)一個(gè)隊(duì)列里,等差不多的時(shí)候就會(huì)引發(fā)一次生命周期更新。
問題分析對(duì)于前兩次setState:
this.setState({value: this.state.val + 1}); console.log(this.state.value); // 第一次輸出 this.setState({value: this.state.val + 1}); console.log(this.state.value); // 第二次輸出
由于setState不會(huì)立即改變React組件中state的值,所以兩次setState中this.state.value都是同一個(gè)值0,故而,這兩次輸出都是0。因而value只被加1。
既然這樣,那么是不是可以直接操作this.state呢?比如:this.state.value=this.state.value+1;
這樣的確可以修改this.state.value的狀態(tài)但是卻不可以引發(fā)重復(fù)渲染。
所以,就必須通過React設(shè)定的setState函數(shù)去改變this.state,從而引發(fā)重新渲染。
setTimeout里面的兩次setState:
setTimeout(() => { this.setState({value: this.state.value + 1}) console.log(this.state.value) // 第三次輸出 this.setState({value: this.state.value + 1}) console.log(this.state.value) // 第四次輸出 }, 0);
這兩次this.state的值同步更新了;
同步更新:是由React引發(fā)的事件處理(比如:onClick引發(fā)的事件處理),調(diào)用setState會(huì)異步更新this.state;
異步更新:除此之外的setState調(diào)用會(huì)同步執(zhí)行this.setState。 “除此之外”指的是:繞過React通過addEventListener直接添加的事件處理函數(shù)和setTimeout/setInterval產(chǎn)生的異步調(diào)用。
this.setState更新機(jī)制圖解:
每次setState產(chǎn)生新的state會(huì)依次被存入一個(gè)隊(duì)列,然后會(huì)根據(jù)isBathingUpdates變量判斷是直接更新this.state還是放進(jìn)dirtyComponent里回頭再說。
isBatchingUpdates默認(rèn)是false,也就表示setState會(huì)同步更新this.state。
但是,當(dāng)React在調(diào)用事件處理函數(shù)之前就會(huì)調(diào)用batchedUpdates,這個(gè)函數(shù)會(huì)把isBatchingUpdates修改為true,造成的后果就是由React控制的事件處理過程setState不會(huì)同步更新this.state。
同步更新(函數(shù)式setState)如果this.setState的參數(shù)不是一個(gè)對(duì)象而是一個(gè)函數(shù)時(shí),這個(gè)函數(shù)會(huì)接收到兩個(gè)參數(shù),第一個(gè)是當(dāng)前的state值,第二個(gè)是當(dāng)前的props,這個(gè)函數(shù)應(yīng)該返回一個(gè)對(duì)象,這個(gè)對(duì)象代表想要對(duì)this.state的更改;
換句話說,之前你想給this.setState傳遞什么對(duì)象參數(shù),在這種函數(shù)里就返回什么對(duì)象。不過,計(jì)算這個(gè)對(duì)象的方法有些改變,不再依賴于this.state,而是依賴于輸入?yún)?shù)state。
function increment(state, props) { return {count: state.count + 1}; } function incrementMultiple() { this.setState(increment); this.setState(increment); this.setState(increment); }
假如當(dāng)前this.state.count的值是0,第一次調(diào)用this.setState(increment),傳給increment的state參數(shù)是0,第二調(diào)用時(shí),state參數(shù)是1,第三次調(diào)用是,參數(shù)是2,最終incrementMultiple讓this.state.count變成了3。
對(duì)于多次調(diào)用函數(shù)式setState的情況,React會(huì)保證調(diào)用每次increment時(shí),state都已經(jīng)合并了之前的狀態(tài)修改結(jié)果。
要注意的是,在increment函數(shù)被調(diào)用時(shí),this.state并沒有被改變,依然,要等到render函數(shù)被重新執(zhí)行時(shí)(或者shouldComponentUpdate函數(shù)返回false之后)才被改變。同步異步setState的用法混合
function incrementMultiple() { this.setState(increment); this.setState(increment); this.setState({count: this.state.count + 1}); this.setState(increment); }
在幾個(gè)函數(shù)式setState調(diào)用中插入一個(gè)傳統(tǒng)式setState調(diào)用,最后得到的結(jié)果是讓this.state.count增加了2,而不是增加4。
這是因?yàn)镽eact會(huì)依次合并所有setState產(chǎn)生的效果,雖然前兩個(gè)函數(shù)式setState調(diào)用產(chǎn)生的效果是count加2,但是中間出現(xiàn)一個(gè)傳統(tǒng)式setState調(diào)用,一下子強(qiáng)行把積攢的效果清空,用count加1取代。
所以,傳統(tǒng)式setState與函數(shù)式setState一定不要混用。
總結(jié)自:掘金(不洗碗工作室)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/52413.html
摘要:除此之外指的是繞過通過直接添加的事件處理函數(shù)和產(chǎn)生的異步調(diào)用。但是,當(dāng)在調(diào)用事件處理函數(shù)之前就會(huì)調(diào)用,這個(gè)函數(shù)會(huì)把修改為,造成的后果就是由控制的事件處理過程不會(huì)同步更新。 拋出問題 class Example extends Component { contructor () { super() this.state = { value: 0, ...
摘要:前端日?qǐng)?bào)精選聽說你沒來總結(jié)個(gè)人使用過的移動(dòng)端布局方法新特性簡(jiǎn)介用寫組件坦然面對(duì)應(yīng)對(duì)前端疲勞中文深入理解筆記函數(shù)前端架構(gòu)經(jīng)驗(yàn)分享系列教程之創(chuàng)建頁面元素龍?jiān)迫珬O盗薪坛讨ㄎ豁撁嬖佚堅(jiān)迫珬5谄谂c表單驗(yàn)證技術(shù)周刊期知乎 2017-07-17 前端日?qǐng)?bào) 精選 聽說你沒來 JSConf 2017?總結(jié)個(gè)人使用過的移動(dòng)端布局方法 - Rni-L - SegmentFaultNode.js v8....
摘要:前端日?qǐng)?bào)精選騰訊前端團(tuán)隊(duì)社區(qū)源碼分析入門指南一些關(guān)于使用的心得基本類型與引用類型知多少掘金中文第期框架選型周刊第期入門系列模塊車棧重構(gòu)基于的網(wǎng)絡(luò)請(qǐng)求庫某熊的全棧之路的那些奇技淫巧的平凡之路模仿寫個(gè)數(shù)組監(jiān)聽掘 2017-07-01 前端日?qǐng)?bào) 精選 Why you shouldn`t use Preact, Fast-React, etc. to replace React today -...
摘要:中的的線程是以事件循環(huán)和消息隊(duì)列的形式存在,包含兩個(gè)任務(wù)隊(duì)列,一個(gè)是內(nèi)部隊(duì)列,一個(gè)是外部隊(duì)列,而的優(yōu)先級(jí)又高于。同時(shí)還有處理按住時(shí)的事件額外處理,同時(shí)手勢(shì)處理一般在的子類進(jìn)行。谷歌大會(huì)之后,有不少人咨詢了我 Flutter 相關(guān)的問題,其中有不少是和面試相關(guān)的,如今一些招聘上也開始羅列 Flutter 相關(guān)要求,最后想了想還是寫一期總結(jié)吧,也算是 Flutter 的階段復(fù)習(xí)。 ??系統(tǒng)完...
閱讀 3151·2021-11-08 13:18
閱讀 2291·2019-08-30 15:55
閱讀 3614·2019-08-30 15:44
閱讀 3075·2019-08-30 13:07
閱讀 2786·2019-08-29 17:20
閱讀 1953·2019-08-29 13:03
閱讀 3419·2019-08-26 10:32
閱讀 3231·2019-08-26 10:15