在react中,因?yàn)閿?shù)據(jù)在某個(gè)節(jié)點(diǎn)被改動(dòng)之后,只會(huì)影響一個(gè)方向上的其他節(jié)點(diǎn);如果是雙向數(shù)據(jù)流父組件的數(shù)據(jù)通過(guò)props傳遞給子組件,而子組件更新了props,導(dǎo)致父組件和其他關(guān)聯(lián)組件的數(shù)據(jù)更新,UI渲染也會(huì)隨著數(shù)據(jù)而更新會(huì)導(dǎo)致數(shù)據(jù)紊亂和不可控制,所以react是單向數(shù)據(jù)流。
本教程操作環(huán)境:Windows10系統(tǒng)、react17.0.1版、Dell G3電腦。
react為什么是單向數(shù)據(jù)流
單向數(shù)據(jù)流就是:數(shù)據(jù)在某個(gè)節(jié)點(diǎn)被改動(dòng)后,只會(huì)影響一個(gè)方向上的其他節(jié)點(diǎn)。
1.你是如何理解單向數(shù)據(jù)流的?
組件的狀態(tài):狀態(tài)可以理解為數(shù)據(jù),與props類(lèi)似,但是state是私有的,并且完全受控于當(dāng)前組件,因此:組件狀態(tài)指的就是一個(gè)組件自己維護(hù)的數(shù)據(jù)。
數(shù)據(jù)驅(qū)動(dòng)UI:意思很簡(jiǎn)單,就是:頁(yè)面所展現(xiàn)的內(nèi)容,完全是受狀態(tài)控制的。這也就是mvvm的理念,UI的改變,全部交給框架本身來(lái)做,我們只需要管理好數(shù)據(jù)(狀態(tài))就好了。
- 那么在 React 中,如何對(duì)狀態(tài)進(jìn)行管理呢?這就是本章節(jié)的重點(diǎn),也是整個(gè) React 學(xué)習(xí)的重點(diǎn):
組件的狀態(tài)管理。
- 什么是數(shù)據(jù)流?
數(shù)據(jù)流就是:數(shù)據(jù)在組件之間的傳遞。
- 單向數(shù)據(jù)流是什么意思?
單向數(shù)據(jù)流就是:數(shù)據(jù)在某個(gè)節(jié)點(diǎn)被改動(dòng)后,只會(huì)影響一個(gè)方向上的其他節(jié)點(diǎn)。
- 為什么是自頂向下的?
就是說(shuō):數(shù)據(jù)只會(huì)影響到下一個(gè)層級(jí)的節(jié)點(diǎn),不會(huì)影響上一個(gè)層級(jí)的節(jié)點(diǎn)。用下面的圖來(lái)說(shuō)就是:L2數(shù)據(jù)改變,只會(huì)影響到L3,不會(huì)影響到L1或者其他的節(jié)點(diǎn)。這就是自頂向下的單向數(shù)據(jù)流。那么我們?cè)趓eact框架中,就可以明確定義單向數(shù)據(jù)流:規(guī)范數(shù)據(jù)的流向,數(shù)據(jù)由外層組件向內(nèi)層組件進(jìn)行傳遞和更新。
- 為什么是單向的?不能是雙向的么?
因?yàn)椋何覀冊(cè)O(shè)想這樣的情景:
父組件的數(shù)據(jù)通過(guò)props傳遞給子組件,而子組件更新了props,導(dǎo)致父組件和其他關(guān)聯(lián)組件的數(shù)據(jù)更新,UI渲染也會(huì)隨著數(shù)據(jù)而更新。毫無(wú)疑問(wèn),這是會(huì)導(dǎo)致嚴(yán)重的數(shù)據(jù)紊亂和不可控制的。
不能是雙向的。
因此絕大多數(shù)框架在這方面做了處理。而 React 在這方面的處理,就是直接規(guī)定了 Props 為只讀的,而不是可更改的。
這也就是我們前面看到的數(shù)據(jù)更新不能直接通過(guò) this.state 操作,想要更新,就需要通過(guò) React 提供的專(zhuān)門(mén)的 this.setState() 方法來(lái)做。
單向數(shù)據(jù)流其實(shí)就是一種框架本身對(duì)數(shù)據(jù)流向的限制。
- 單向數(shù)據(jù)流有什么作用呢?
保證數(shù)據(jù)的可控性。
2.setState 是同步還是異步的呀?
- setState 本身的默認(rèn)行為是什么?
其實(shí)也很簡(jiǎn)單,我們都知道,setState可以傳遞對(duì)象形式的狀態(tài),也可以傳遞函數(shù)形式的狀態(tài)。而不論狀態(tài)是對(duì)象形式還是函數(shù)形式,它都會(huì)先將所有狀態(tài)保存起來(lái),然后進(jìn)行狀態(tài)合并,所有狀態(tài)合并完成后再進(jìn)行一次性 DOM 更新。
- 如果狀態(tài)是對(duì)象形式,后面的狀態(tài)會(huì)直接覆蓋前面的狀態(tài)。類(lèi)似于 Object.assign() 的合并操作。
對(duì)于對(duì)象狀態(tài)這一點(diǎn),我們看下代碼:
運(yùn)行以上代碼,Dom 中展示的結(jié)果為 1。很顯然兩次 setState 只有一次生效了。
真的嗎?其實(shí)兩次都有生效,只不過(guò)這兩次 setState 在執(zhí)行前,被合并成了一個(gè)。你不能說(shuō)到底是那個(gè)生效,你可以說(shuō)兩個(gè)都沒(méi)生效,因?yàn)樽罱K執(zhí)行的是被合并的那個(gè)代碼。
- 如果狀態(tài)是函數(shù)形式,那么依次調(diào)用函數(shù)進(jìn)行狀態(tài)累積,所有函數(shù)調(diào)用完成后, 得到最終狀態(tài),最終進(jìn)行一次性 DOM 更新。
明顯不一樣的結(jié)果就能說(shuō)明,兩次都執(zhí)行了,因?yàn)楹瘮?shù)狀態(tài)并不會(huì)合并,而是以此運(yùn)行。