圖解 Flux
在如今的 Web 開發領域,Flux 最流行也最容易被大家所誤解的技術之一。本教程打算以一種大家都能理解方式圖解 Flux。
問題
首 先我必須先解釋一下 Flux 到底解決什么問題。Flux 是一種應用處理的數據的模式。雖然 Flux 和 React 一同在 非死book 成長起來的,很多人把它們合到一起來理解,但你可以單獨使用它們。它們是被設計來解決一些 非死book 碰到的一系列問題的。
一 個眾所周知的例子就是關于通知的 Bug。當你登錄 非死book 后,可能會看到在消息 icon 上有一個通知。當你點擊消息 icon,卻發現并沒有新的消息,然后通知不見了。幾分鐘之后,你在網頁上做了一些交互,通知又回來了,你再一次點擊消息 icon……但并沒有新消息。然后就進入周而復始的循環。
這種循環不僅僅影響了網站的用戶,還包含 非死book 的開發團隊。他們修復這個問題,一段時間內是 OK 的,但這個 Bug 過段時間又會出現。周而復始,一下被解決了,一下又有問題。
因此 非死book 試圖尋找解決方案來跳出這個怪圈,而不是一次次地修復它。他們希望可以打造一個確定的系統,以此確保這個問題不會反復出現。
深層問題
非死book 的工程師發現,更深層次的問題來自應用的數據傳遞問題。
注意:我是從他們簡化版的分享中了推測出來的。我確定真實的架構可能是不一樣的。
他們用 Model 保存數據,并把數據傳遞一個 View 層,把這些數據渲染出來。
由于用戶通過 View 層來交互,View 有時需要根據用戶的數據更新 Model。還有時 Model 需要更新其他的 Model。
在這種情況下,有時候有些操作會觸發一連串的變化。我把這想象成一種激動人心的乒乓游戲——很難判斷球的落點在哪里(或者是跑到了屏幕之外。)
還有一個這樣的事實,有些變化可能是異步的。一個變化會引起多個其他的變化。我想象下就像在乒乓游戲了直接撒了一袋子乒乓球,它們散落在各個地方,并互相穿梭。
總而言之,這使得數據流變得很難調試。
解決方案:單向數據流
因此 非死book 決定嘗試另外一種架構,即單向數據流——就一個方向——當你需要插入新的數據,流完全重新開始。他們把這種架構稱為 Flux。
在 非死book 的 Flux 文檔中也可以找到這張圖,本身要比看起來更酷,真的,非常酷……但光看上面這張圖可能無法完全明白。
一旦你理解了 Flux,這張圖看起來就比較清晰了。可問題是,你剛看到文檔,對 Flux 完全是陌生的,我就不信這張圖有助于你對它的立即……但這確實是圖需要做的事情。它應該給你一個大的概念,在深入進去搞清楚各個細節之前。
幫助我更好理解 Flux 的并不是像這樣的一張圖,而是把這個系統想象成多個不同的角色一起協作實現一個共同的目標。因此我想給大家介紹一下我大腦中的演職表。
演職表
在我解釋這些角色間如何交互前,先逐個介紹下它們。
Action Creator
第一個角色是 Action Creator。它負責創建 Aaction,作為全部改變和交互的入口。當需要改變應用的狀態或有 View 需要更新時,你需要觸發一個 Action。
我認為 Action Creator 就像電報員。你拿著你想要寄出的消息,找到 Action Creator,它就把消息格式化成系統其他部分可以理解的形式。
Action Creator 把 type 和 payload(載荷)封裝成一個 Action。type 是你預定義的多個 type (通常是一個常量列表)之一,代表系統特定的 action。舉個例子的話就像 MESSAGE_CREATE 和 MESSAGE_READ 這樣的。
系統的某個部分知道所有可能的 action,這或許存在副作用。一個新來的工程師,打開 Action Creator 文件,看到全部的 API——所有可能改變的狀態——它們都是你的系統提供的。
一旦 action 消息創建好了,Action Creator 就會把它傳遞給 Dispatcher。
Dispatcher
Dispatcher 就是一個巨大的回調函數登記表。就好比一個坐在電話總機前的接線員。它保存著所有需要發送 action 的 store 列表。當 Action Creator 給過來一個 action,它會把這個 action 傳遞給各個 store。
Dispatcher 的行為是同步的,這對我之前講的多個乒乓球游戲有所幫助。如果想要在 store 之間實現依賴,有的更新完了其他的才能更新,你可以使用 Dispatcher 提供的 waitFor() 來實現。
Flux 的 Dispatcher 不同于其他大部分架構中的 dispatcher。它會把 action 傳遞給所有登記在冊的 store,而不在 action 的類型。也就是說 store 并不是訂閱某些 action,而是聆聽每一個 action,從中過濾它關心的。
Store
輪到說 store 了。store 保存了整個程序的狀態,而且狀態變化的邏輯都在 store 里。
我 覺得 store 就是一個充滿控制欲的長官。所有所有的狀態變化都必須由它來親自操作的。而且你不能直接通過 store 來更改狀態。在 store 上并沒有 setter API。要更新一次狀態,你必須經過正當的手續——必須通過 Action Creator/Dispatcher 通道。
上 面說了,如果 store 在 dispatcher 中注冊了,那所有的 action 都會發給它。在 store 中,通常會使用一個 switch 語句來判斷 action 的類型,決定是否最這個 action 做出相應。如果 store 關心這個 action,就會根據 action 找出需要變化的部分,更新 state。
只要 store 對 state 做出了變更,就會出發 change 事件,通知視圖控制器狀態已經變化了。
Controller View 和 View
View 層負責將 state 渲染給用戶,并接受用戶的輸入。
View 就像一個主持。它對應用一無所知,只懂該如何把交到它們手中的數據渲染格式化成用戶能夠理解的輸出(HTML)。
Controller View 是一個中間管理者。store 在 state 變化時通知它,它收集新的狀態,并將更新后的狀態傳遞給所有大管轄的 View。
它們如何在一起工作?
接下來看看這些角色是如何在一起工作的。
開始
首先在應用啟動時:啟動只有一次。
-
Store 告知 Dispatcher 只要有 action 產生就通知它。
</li> -
Controller View 從 Store 中獲取最新的 state。
</li> -
當 Controller View 接到來自 store 的 state,就將其傳遞給它所管轄的子 View 去渲染。
</li> -
Controller View 同時讓 store 在 state 變化的時候通知自己。
</li> </ol>數據流
應用啟動后,就準備好接受用戶的輸入了。現在我們讓用戶做一些操作,觸發一個 action。
用戶交互我們就產生一次數據流。
-
View 告知 Action Creator 準備一個 action。
</li> -
Action Creator 做好 action 并將其發送給 Dispatcher。
</li> -
Dispatcher 按照順序將 action 傳遞給 store。每一個 store 都會受到所有的 action 通知,然后自行覺得是否對這個 action 做出響應,更新 state。
</li> -
一旦 store 更新 state 完畢,就會告知訂閱了該 store 的 controller view。
</li> -
這些 controller view 就會向 store 請求更新了的 state。
</li> -
從 store 中獲得 state 之后,view controller 將會讓它所管轄的子 view 渲染新的 state。
</li> </ol>好了,這些就是我對 Flux 的理解,希望能夠幫助到你!
資源
-