JavaScript狀態(tài)機(jī)的理解

##有限狀態(tài)自動(dòng)機(jī),簡(jiǎn)稱狀態(tài)機(jī),是表示有限個(gè)狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動(dòng)作等行為的數(shù)學(xué)模型。

React和React Native的狀態(tài)

##有限狀態(tài)機(jī)(Finite-state machine)是一個(gè)非常有用的模型,可以模擬世界上大部分事物。

簡(jiǎn)單說,它有三個(gè)典型特征:

1:事物包含的狀態(tài)總數(shù)(state)是有限的。

2:任一時(shí)刻,事物僅且只能處于一種狀態(tài)之中。

3:某種事件驅(qū)動(dòng)下,可以導(dǎo)致事物從一種狀態(tài)切換到另一種狀態(tài)。

在維基百科中稱:有限狀態(tài)機(jī)FSM是設(shè)計(jì)和實(shí)現(xiàn)事件驅(qū)動(dòng)程序內(nèi)復(fù)雜行為組織原則的有力工具。

傳統(tǒng)的MVC設(shè)計(jì)中

它對(duì)JavaScript的意義在于,很多對(duì)象可以寫成有限狀態(tài)機(jī)。

有限狀態(tài)機(jī)的寫法,邏輯清晰,表達(dá)力強(qiáng),有利于封裝事件。一個(gè)對(duì)象的狀態(tài)越多、發(fā)生的事件越多,就越適合采用有限狀態(tài)機(jī)的寫法。

另外,JavaScript語(yǔ)言是一種異步操作特別多的語(yǔ)言,常用的解決方法是指定回調(diào)函數(shù),但這樣會(huì)造成代碼結(jié)構(gòu)混亂、難以測(cè)試和除錯(cuò)等問題。有限狀態(tài)機(jī)提供了更好的辦法:把異步操作與對(duì)象的狀態(tài)改變掛鉤,當(dāng)異步操作結(jié)束的時(shí)候,發(fā)生相應(yīng)的狀態(tài)改變,由此再觸發(fā)其他操作。這要比回調(diào)函數(shù)、事件監(jiān)聽、發(fā)布/訂閱等解決方案,在邏輯上更合理,更易于降低代碼的復(fù)雜度。

有限狀態(tài)機(jī)非常重要的一點(diǎn)就是講用戶的操作行為,也就是組件的事件響應(yīng)與組件的表現(xiàn)分離開來(lái).通過建立一個(gè)有限狀態(tài)機(jī)的組件時(shí),我們完全不關(guān)心用戶的操作行為具體做了什么,這時(shí)組件可能會(huì)有幾種狀態(tài)對(duì)應(yīng)不同的表現(xiàn)形式,而用戶觸發(fā)的事件僅僅是切換了模型的狀態(tài).至于每個(gè)狀態(tài)的具體表現(xiàn)和行為,我們完全可以單獨(dú)定義,也就說這時(shí)一種行為和響應(yīng)上的解耦.

當(dāng)用戶的操作發(fā)生變化的時(shí)候,我們僅僅需要改變根數(shù)據(jù),也就是state源.而不需要像以往的MVC設(shè)計(jì)中,當(dāng)行為發(fā)生時(shí),我們既需要在C層改變Model,同時(shí)還要操作View進(jìn)行更新.在復(fù)雜的交互場(chǎng)景中代碼尤其臃腫難以維護(hù).狀態(tài)機(jī)的設(shè)計(jì)思路,很好的解決了這個(gè)問題,用戶操作行為僅僅與修改數(shù)據(jù)關(guān)聯(lián),而與其他無(wú)關(guān).

React框架中將UI簡(jiǎn)單的看作有點(diǎn)狀態(tài)機(jī)的組件集合。將UI看作包含了各種各樣的狀態(tài)的組件,并在各種狀態(tài)間切換,很容易保持UI的一致性。在React中,你只要改變組件的狀態(tài),就會(huì)自動(dòng)重新渲染UI,React會(huì)在最有高效的方式下更新虛擬DOM。

通過調(diào)用setState(data, callback)方法,改變狀態(tài),就會(huì)觸發(fā)React更新UI。大部分情況下,我們不需要提供callback函數(shù)。React會(huì)自動(dòng)的幫我們更新UI。

后面在好好看看這個(gè)callback的功能和調(diào)用時(shí)機(jī)。

使用React組件時(shí),免不了就需要跟props,state這兩個(gè)屬性打交道.

props是從父組件或者組件創(chuàng)建時(shí)外部傳遞來(lái)的,大多數(shù)組件在創(chuàng)建時(shí)就可以使用各種參數(shù)來(lái)進(jìn)行定制,這些定制的參數(shù)就props,props是在父組件中指定,而且一經(jīng)指定,在被指定的組件的生命周期中則不再改變

state也是用來(lái)控制描述一個(gè)組件的,對(duì)于需要改變的數(shù)據(jù),我們需要使用state。

那么什么樣的組件該有state呢?

大部分的組件應(yīng)該從props屬性中獲取數(shù)據(jù)并渲染。但有的時(shí)候組件得相應(yīng)用戶輸入或者交互響應(yīng),或同服務(wù)器交互,這些情況下會(huì)用到state。React的官方說法是:盡可能的保持你的組件無(wú)狀態(tài)化(個(gè)人的理解就是更好的貼合單向數(shù)據(jù)流這一理念)。為了實(shí)現(xiàn)這個(gè)目標(biāo),得保持你的狀態(tài)同業(yè)務(wù)邏輯分離,并減少冗余信息,盡可能保持組件的單一職責(zé)。

state應(yīng)該包含什么樣的數(shù)據(jù)

UI交互,服務(wù)器交互,會(huì)導(dǎo)致改變的數(shù)據(jù)。

state不應(yīng)包含什么樣的數(shù)據(jù)

1.計(jì)算過的數(shù)據(jù)

2.組件

3.從props復(fù)制的數(shù)據(jù)

React官方推薦的一種模式就是:構(gòu)建幾個(gè)無(wú)狀態(tài)的組件用來(lái)渲染數(shù)據(jù),在這些之上構(gòu)建一個(gè)有狀態(tài)的組件同用戶和服務(wù)交互,數(shù)據(jù)通過props傳遞給無(wú)狀態(tài)的組件。

React的作者認(rèn)為,組件應(yīng)該同關(guān)注分離,而不是同模板和展現(xiàn)邏輯分離。結(jié)構(gòu)化標(biāo)記和生成結(jié)構(gòu)化標(biāo)記的代碼是緊密關(guān)聯(lián)的,此外,展現(xiàn)邏輯一般都很復(fù)雜,使用模板語(yǔ)言會(huì)使展現(xiàn)變得笨重。

React解決這個(gè)問題的方式就是:直接通過JavaScript代碼生成虛擬Dom和組件樹,這樣的話,你就可以使用JavaScript富豐的表達(dá)力去構(gòu)建UI。為了使這個(gè)過程變得更簡(jiǎn)單,React創(chuàng)建了類似HTML的語(yǔ)法去構(gòu)建節(jié)點(diǎn)樹,也就是JSX了。這樣可以更方便的創(chuàng)建模板化的組件,方便代碼復(fù)用.

如果一個(gè)組件的數(shù)據(jù)都是不變的,這意味著UI顯示部分也是不變的,那么它就不應(yīng)當(dāng)成為一個(gè)單獨(dú)的RN組件,因?yàn)閱为?dú)的RN組件肯定是數(shù)據(jù)會(huì)被改變的.

對(duì)于無(wú)狀態(tài)的RN組件來(lái)說,會(huì)被改變的數(shù)據(jù)來(lái)自于它的props(屬性),而對(duì)于有狀態(tài)的RN組件來(lái)說,會(huì)被改變的數(shù)據(jù)不僅來(lái)自于它的props,還來(lái)自于它的state(狀態(tài)機(jī)變量).盡可能的讓自定義的組件成為無(wú)狀態(tài)的RN組件,以為者盡可能的讓自定義的RN組件沒有狀態(tài)機(jī)變量.

一個(gè)好的設(shè)計(jì)思路是:

創(chuàng)建多個(gè)只負(fù)責(zé)渲染的無(wú)狀態(tài)的RN組件,將他們封裝在一個(gè)有狀態(tài)的RN組件中,并把這個(gè)有狀態(tài)的RN組件的狀態(tài)機(jī)變量的值通過props的形式傳遞給無(wú)狀態(tài)的RN組件中.在這種設(shè)計(jì)思路下,有狀態(tài)的RN組件封裝了UI的交互邏輯,而無(wú)狀態(tài)的RN組件只負(fù)責(zé)渲染UI界面.

但是狀態(tài)機(jī)變量的改變會(huì)導(dǎo)致RN組件的重新渲染,所以提高RN應(yīng)用程序性能的一種方式就是努力減少狀態(tài)機(jī)變量的數(shù)目.

在RN組件的render函數(shù)中,在正確的位置引用狀態(tài)機(jī)變量.

組件之間的通信:

父組件向子組件傳遞消息,數(shù)據(jù)通過回調(diào)父組件傳遞給自己的回調(diào)函數(shù)來(lái)實(shí)現(xiàn).回調(diào)函數(shù)于父組件設(shè)定,被保存在子組件的某個(gè)屬性中,等待需要向父組件傳遞消息的時(shí)候調(diào)用.

除了setState函數(shù)意外,RN還提供了replaceState函數(shù)與forceUpdate函數(shù)

狀態(tài)機(jī)的優(yōu)點(diǎn):

1)有限狀態(tài)機(jī)是定義組件的一種好用的設(shè)計(jì)模式,能夠讓組件的代碼看起來(lái)更加清晰,而且易于理解;

2)有限狀態(tài)機(jī)這種模式適合有明顯狀態(tài)特點(diǎn)的組件;

3)本文所舉的例子不夠貼近實(shí)際項(xiàng)目,近期會(huì)看看自己做過的項(xiàng)目中有哪些適合用狀態(tài)機(jī)模式來(lái)重寫的模塊,到時(shí)候再寫博客來(lái)與大家分享。

有一個(gè)異步操作(light.fadeOut)。如果不希望狀態(tài)立即改變,就要讓回調(diào)函數(shù)返回StateMachine.ASYNC,表示狀態(tài)暫時(shí)不改變;等到異步操作結(jié)束,再調(diào)用transition方法,使得狀態(tài)發(fā)生改變。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容