Redux裏的強硬規則與設計很多,大部份都會與FP(函數式程序開發)、改進本來的Flux架構設計有關。Redux官網文檔上的三大基本原則,主要是由於有可能怕初學者不理解Redux中的一些限制或設計,因此先寫出來講明,這裏面也說明了Redux的設計原理基礎是如何,因此強烈建議全部的初學者必定要完全地理解這三大原則中的意義,多看幾遍,對往後的學習會頗有幫助。如下分別說明,主要以原文的標題與內容說明,盡能夠說明的比較清楚些。html
你的整個應用中的state(狀態),會存儲在單一個store(存儲)之中的一個對象樹狀結構裏。git
Redux中只有用單一個對象大樹結構來的存儲整個應用的狀態,也就是整個應用中會用到的數據,稱之爲store
(存儲)。但要注意的是store
(存儲)並非只有單純的數據而已。store
就是應用程序領域的狀態,它是類型MVC中的Model(模型的)設計的概念,這設計是由Flux架構而來的,在本來的Flux架構中是容許多個store
的結構,Redux簡化爲只有單一個。github
Redux的單一個store的設計有一些好處,對開發者來講,它能夠容易調試與觀察狀態的變化,狀態存儲於對象樹狀結構中,也很容易做到重做/復原(Undo/Redo)的功能。由於只有一個store
,但若是store
裏要儲放多個不一樣的狀態對象,以及每次的更動數據,天然就會變成了對象樹狀結構(object tree)。redux
此外,若是你想要從store中取出目前的狀態數據,能夠用store的getState()
方法。數組
惟一能更動狀態的是發送一個
action
(動做),action
是一個描述"發生了什麼事"的純對象架構
這裏指的"狀態",是上面說的儲放在store中的狀態數據,你"不能直接"對其中的狀態數據更動,只能"間接"地做這事。這與原先的React中的state
與setState
的概念有點像,Redux的意思是你不能直接更動store
裏面所記錄的狀態值,只能"間接"地透過發送action
對象來叫store
更動狀態。"間接"地更動狀態是一個很關鍵的設計,這是Flux中單向數據流的重點之一,這對於每一個動做發生,最終會影響到什麼狀態上的更動,一個接一個的順序等等的一種嚴格的設計。函數
你可能會認爲"狀態既然是惟讀",直接與間接有什麼差別,"惟讀"不就表明徹底不能更動,這語句是否是有誤?學習
"惟讀"固然就是徹底不能更動的意思沒錯,因此狀態對象的更動是並非在原先的狀態對象上變更它,而是由原先狀態對象由於動做的加入後,產生一個全新的狀態對象,用這全新的狀態對象來取代原先的狀態對象而已。這在真實世界中或許很難拿比喻來講明,但在軟體世界中這很能夠很容易達成。spa
"發生了什麼事"這句,是表明每一個action
都會有一個type(類型),表明這個動做是要做什麼用的,或是如今是發生了什麼,例如是要新建一筆什麼數據,或是刪除整個數據等等,動做對象除了要說明它是要做什麼以外,也須要包含所影響的數據。架構設計
發送一個action(動做),使用的是store.dispatch(action)
語法樣式,下面這個例子就是一個要更動狀態的代碼:
store.dispatch({ type: 'COMPLETE_TODO', index: 1 })
中間的那個純對象,就叫做action
(動做),它是一個單純用於描述發生了什麼事與相關數據的純對象:
{ type: 'COMPLETE_TODO', index: 1 }
還記得咱們在React中的state
與setState
方法的設計嗎?state
也是不能直接更動的,必定要透過setState
方法才能更動它。那這是爲何呢?由於setState
不光只是更動state
值,它還要做從新渲染的動做,React須要比對目前的狀態,與即將要變更的狀態,這樣才能進移動新渲染的工做。Redux的設計中store
是與React中的state
相比,它們之間有一些相似的設計。
要指示狀態樹要如何依actions(動做)來做改變,你須要撰寫純粹的概括函數(reducers)
Redux中的reducer的原型會長得像下面這樣,你能夠把它看成就是 以前的狀態 + 動做 = 新的狀態
的公式:
(previousState, action) => newState
注: 你能夠參考Redux中Reducers這一章的內容,裏面有實例。
不過,Redux中的reducer必定是純函數(pure function),也就是不能有反作用的函數。所以由reducer所產生的新狀態,並非直接修改以前的狀態而來,而是一個複製以前狀態,而後加上動做改變的部份,產生的一個新的對象,它這樣設計是有緣由的。
Redux的store設計,並非本來Flux架構中的store,而是ReduceStore,這個ReduceStore是一個在Flux中的store
進化版本,在說明中它有一個叫做reduce的方法,說明以下:
reduce(state: T, action: Object): T 概括(Reduces)目前的state(狀態)與一個action(動做)到新的store中的state(狀態)。全部的子類都須要實做這個方法。這個方法必須是純粹而是無反作用。
那爲什麼要用這個進化的ReduceStore?它最後有說明一段:
不須要發送更動事件注意全部繼承自ReduceStore的store,不須要手動發送在reduce()中的更動事件...state(狀態)會自動地比對在每一個dispatch(發送)以前與以後,與自動地做發送更動事件...
ReduceStore
的設計與Redux最一開始的版本差很少是同時間發佈的,在開發者之間彼此有交流。Redux的store運用了相似於ReduceStore的設計,因此要更動Redux中的store,須要透過reducer,這是爲了簡化本來在Flux數據流的實做流程。
reducer在Redux中扮演了十分重要的關鍵角色,它是一種對store中所存放的狀態,要如何因應不一樣的動做而進行刷新的函數,而store也是由reducer所建立,例如像下面的代碼:
// @Reducer // // action payload = action.text // 使用純粹函數的數組unshift,不能有反作用 // state(狀態)一開始的值是空數組`state=[]` function todoApp(state = [], action) { switch (action.type) { case 'ADD_ITEM': return [action.text, ...state] default: return state } } // @Store // // 由reducer建立store const store = createStore(todoApp)
針對應用中不一樣功能的狀態,能夠分別寫出不一樣的reducer,Redux中提供了combineReducers
函數能夠合併多個reducer,例如如下的代碼:
function todos(state = [], action) { switch (action.type) { case 'ADD_TODO': return state.concat([ action.text ]) default: return state } } function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } } // rootReducer是個組合過的函數, // 這裏用的是對象屬性初始設置簡寫法, // combineReducers傳參是一個對象 const rootReducer = combineReducers({ todos, counter })