我以爲應該有很多同窗和我同樣,上來學React,以爲甚是驚豔,看着看着,發現facebook 安利了一個flux
,圖畫的巨複雜,而後各類例子都有用這個東西,沒辦法,硬着頭皮看。看得似懂非懂,而後忽然你們又都推薦Redux
,號稱最簡單的flux-like
的實現,結果實現的源碼是很簡單,可是文檔是源碼的幾十倍,概念甩一臉,寫個簡單東西,要建十幾個文件,寫得雲裏霧裏。html
有沒有想到,爲何要用Flux這類東西?本篇的定位是讓你們知道有個脈絡,因此不會太注意措辭的準確性.react
React只是一個view層的解決方案,光有界面沒用,還得加上數據才行。React經過props
和state
去渲染界面,因此有個很形象的描述UI = f(props,state)
.android
有數據,就有數據通訊的問題。react是單向數據流,父組件經過props
把數據傳遞給子組件。可是數據的流向不可能只有這一種。git
祖父組件到孫子組件。
這個看上去只是父到子的衍生,可是祖祖祖父到孫子組件呢。這個react在(好像是)0.13時經過context
基本解決了,關於context,以前沒接觸的同窗,能夠看文檔github
子到父。下面是一種方案:父給子傳遞一個函數,子在只要調用這個函數,父就能獲得相關的數據。可是孫子到祖祖祖父呢。。編程
非父子關係:基本能夠叫作是兄弟關係,以網頁爲例,總歸有一個共同的祖先<body>
,可是有多是很是很是遠的兄弟。這個怎麼處理。redux
組件的一些關係和相應的通訊方式,官方有簡單的說明,見文檔設計模式
對於上面的2
,3
兩點,用react本事的機制,寫出來都很彆扭,特別是第3點。兩個不相關的地方,要數據通訊,最簡單就是一個全局變量
嗎。固然光有全局變量還不行,你改了全局變量,其餘全部對這個變量感興趣React組件的都要被通知到
,這樣才能相應改變界面。你若是接觸到設計模式,應該能想到觀察者模式
(中介者模式
也能夠,實際上flux更像中介者中,不過觀察者應該接受度更高點,並且這裏不影響理解)。服務器
其實官方文檔中,也有些小線索。angular2
For communication between two components that don't have a parent-child relationship, you can set up your own global event system. Subscribe to events in componentDidMount(), unsubscribe in componentWillUnmount(), and call setState() when you receive an event. Flux pattern is one of the possible ways to arrange this.
這段的關鍵是you can set up your own global event system
。因此你只要去研究之前各類事件系統是怎麼設計,就能夠本身擼一套 **ux
了。
梳理了一下,React須要配合Flux-Like
的庫去使用,是由於要解決通訊問題。通訊的關鍵有一下幾點:
數據,這個不用說的吧。由於react中,經過setState去觸發改變界面,命名成state
各類事件,叫event
可能更直觀,可是你們都叫它action
,一個意思,發生了一個動做。這個動做有一下幾個關鍵屬性:什麼動做,誰發出的(這個我看各個類flux庫中,好像都沒處理),有沒有額外信息嗎。
事件發生,要分發出去,包括改變數據,而後通知給全部監聽數據變化的Listeners
註冊監聽者。
這些都是你們能想象到。好了,根據這幾點,一個簡單的Myux
就能夠寫了
class Myux{ state:{}, actionTypes:{}, dispatch(){}, subscribe(){} listeners:[] }
與上面四個組成部分項對應。來個例子吧,以計數器爲例吧。
class CountStore{ static actionTypes:{ UP:'UP', //你英語好,你用increase DOWN:"DOWN" } state:0 //數據,計數開始是零 listeners:[] dispatch(actionType){ if(actionType === CountStore.actionTypes.UP){ this.state++; } if(actionType === CountStore.actionTypes.DOWN){ this.state--; } this.listeners.forEach((ln)=>{ ln(actionType,this,undefined)//對應什麼動做,誰發出的,額外信息。 }) } subscribe(ln){ this.listeners.push(ln) //返回一個函數,調用,就取消註冊 return ()=>{ const index = this.listeners.indexOf(ln); if(index !== -1){ this.listeners.splice(index,1) } } } }
react的組件裏,只要註冊成listener,而後state發生變化,被通知到,調用setState
進行視圖更新就好。
class CountComponent extends React.Component{ constructor(props,context){ super(props,context) const store = this.props.store; this.state = store.getState(); } componentDidMount(){ this.unsubscribe = store.subscribe((actionType,store)=>{ if(this.state !== store.getState()){ this.setState(store.getState()); } }) } componentWillUnmount(){ if(typeof this.unsubscribe === 'function'){ this.unsubscribe(); } } render(){ const state = this.state return <div>{state}</div> } }
使用嗎,直接mount到body上,會報warning,忽略...
const countStore = new CountStore() ReactDOM.render( <CountComponent store={countStore}/>, document.body )
這樣,只要在任何地方,countStore.dispatch(upOrDown)
,CountComponent
裏的數字就會加加減減。
能夠想一想一下,若是頁面有2,3個組件要根據計數器的數值,作界面的相應變化,都是能夠輕鬆知足的。
固然,若是隻有一個組件用須要這個store,那麼單純代碼上,這樣寫,要多寫不少東西。可是誰知道之後頁面不會加一個要共用這個store的組件,這時候這個store
就是組件間通訊的法寶了。
上面只有一個store,這是store還只有一個state,這個太簡單了。實際,你的應用可能要維護多個狀態。怎麼辦
一個store裏一個state,而後多個store
ListStore => ListState DetailStore => DetailState
全局就一個store,state是一個狀態樹,整個應用須要的state,都在這個樹裏。
GlobalStore => state:{list:[],detail:{}} //...
還有一個問題dispatch
,是全局一個dispatch
,仍是每一個store一個dispatch
。
這些分歧,加上函數式等,就致使了有flux
,reflux
,redux
。。
還有各個事件之間,有可能存在依賴關係,A事件後,B也觸發。又要加waitFor
和中間件
等概念。不過總體來講,就這些東西。
redux的文檔裏,有三大原則,有了上面的概念,咱們來對照看一下
Single source of truth:就是更改應用一個state tree,儲存在一個store裏,這種狀況,也只能有一個dispatch
State is read-only:state是全局的,若是不是隻讀的,很難維護。這個上面沒有體現,可是也是很天然的想法。
Mutations are written as pure functions:這個算redux
最大的特色,引入了reducers
的概念,和第二點有相輔相成的感受。
另外還有中間件系統。二、3兩點,實際上是函數式編程的基本概念,不變量
和pure function
。相比於傳統的事件系統,Redux融入了很多functional reactive programming(FRP)的思想。
單dispatch,多store多state,用waitFor
處理store的依賴。
多dispatch,多store多state。這個並沒實際用過,看文檔,應該是這樣的。有問題,請提出。
如今有種趨勢,傳統的事件系統逐漸讓你們以爲low b,functional reactive programming(FRP)高大上。Redux
有一些FRP的思想,被你們以爲比Flux高大上,可是不是很複雜的項目,應該會有:臥槽,那麼簡單的東西,爲毛有那麼多文件,寫得那麼繞的感受。
angular2中,RxJS
將會是最大的門檻之一。
我以爲把,從能解決問題的複雜度上,FRP的確比傳統的事件系統高級,可是概念也更多,不是特複雜的程序,這些概念只會增長你的開發難度,而且對後面維護的人要求更高。
Java那麼多年,沒RxJava
,服務器端,android端,那麼多年也挺過來了,雖然先進,不必定合適。咱們如今本身的項目,使用的就是本身擼的一個小東西。對咱們如今的規模,開發和維護都挺好的。