Redux 是 JavaScript 狀態容器,提供可預測化的狀態管理。
Redux 是在 Flux 的基礎上產生的,基本思想是保證數據的單向流動,同時便于控制、使用、測試。Redux 并不依賴于其它 JavaScript 庫。
隨著 JavaScript 單頁應用開發日趨復雜,JavaScript 需要管理比任何時候都要多的 state (狀態)。 這些 state 可能包括服務器響應、緩存數據、本地生成尚未持久化到服務器的數據,也包括 UI 狀態,如激活的路由,被選中的標簽,是否顯示加載動效或者分頁器等等。
跟隨 Flux、CQRS 和 Event Sourcing 的腳步,通過限制更新發生的時間和方式,Redux 試圖讓 state 的變化變得可預測。這些限制條件反映在 Redux 的三大原則中:
單一數據源。整個應用的 state 被儲存在一棵 object tree 中,并且這個 object tree 只存在于唯一一個 store 中。
Redux 主要分為三個部分 Action、Reducer、及 Store
Action。Action 很簡單,就是一個單純的包含 { type, payload } 的對象,type 是一個常量用來標示動作類型,payload 是這個動作攜帶的數據。Action 需要通過 store.dispatch() 方法來發送。嚴格的單向數據流是 Redux 架構的設計核心。store.dispatch(action) -> reducer(state, action) -> store.getState() 構成了一個“單向數據流”。
Redux 應用中數據的生命周期遵循下面 4 個步驟:
調用 store.dispatch(action)。Flux 是一種應用架構,或者說是一種思想,它跟 React 本身沒什么關系,它可以用在 React 上,也可以用在別的框架上。
Flux 主要包括四個部分,Dispatcher、Store、View、Action,其中 Dispatcher 是 Flux 的核心樞紐,它相當于是一個事件分發器,將那些分散在各個組件里面的邏輯代碼收集起來,統一在 Dispatcher 中進行處理。
完整的 Flux 處理流程是這樣的:用戶通過與 view 交互或者外部產生一個 Action,Dispatcher 接收到 Action 并執行那些已經注冊的回調,向所有 Store 分發 Action。通過注冊的回調,Store 響應那些與他們所保存的狀態有關的 Action。然后 Store 會觸發一個 change 事件,來提醒 controller-views 數據已經發生了改變。Controller-views 監聽這些事件并重新從 Store 中獲取數據。這些 controller-views 調用他們自己的 setState() 方法,重新渲染自身以及組件樹上的所有后代組件。
Redux 的靈感來源于 Flux 的幾個重要特性,它可以看作是 Flux 的一種實現。和 Flux 一樣,Redux 規定,將模型的更新邏輯全部集中于一個特定的層,都不允許程序直接修改數據,而是用一個叫作 “action” 的普通對象來對更改進行描述。不同的是:
Redux 只有一個 store。 Flux 里面會有多個 store 存儲應用數據,并在 store 里面執行更新邏輯,當 store 變化的時候再通知 controller-view 更新自己的數據,Redux 將各個 store 整合成一個完整的 store,并且可以根據這個 store 推導出應用完整的 state。同時 Redux 中更新的邏輯也不在 store 中執行而是放在 reducer 中。 應用中所有的 state 都以一個對象樹的形式儲存在一個單一的 store 中。唯一改變 state 的辦法是觸發 action,一個描述發生什么的對象。
為了描述 action 如何改變 state 樹,需要編寫 reducers。
- // 這是一個 reducer,形式為 (state, action) => state 的純函數。
- function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1; case 'DECREMENT': return state - 1; default: return state;
- }
- } // 創建 Redux store 來存放應用的狀態
- let store = createStore(counter); // 可以手動訂閱更新,也可以事件綁定到視圖層。
- store.subscribe(() => console.log(store.getState())
- ); // 改變內部 state 唯一方法是 dispatch 一個 action。
- store.dispatch({ type: 'INCREMENT' }); // 輸出:1
- store.dispatch({ type: 'INCREMENT' }); // 輸出:2
- store.dispatch({ type: 'DECREMENT' }); // 輸出:1
以上代碼,首先定義改變應用狀態的對象,這個對象被叫做 action,而不是直接改變 state。然后編寫專門的函數來決定每個 action 如何改變應用的 state,這個函數被叫做 reducer。
Redux只有一個單一的 store 和一個根級的 reduce 函數(reducer)。
隨著應用越來越大,一方面,不能把所有的數據都放到一個reducer里面,另一方面,為每個reducer創建一個store,后續store的維護就顯得比較麻煩。combineReducers 輔助函數的作用是,把一個由多個不同 reducer 函數作為 value 的 object,合并成一個最終的 reducer 函數,然后就可以對這個 reducer 調用 createStore。合并后的 reducer 可以調用各個子 reducer,并把它們的結果合并成一個 state 對象。state 對象的結構由傳入的多個 reducer 的 key 決定。
- // 創建兩個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
- }
- } // 將多個reducer合并成一個
- var combineReducers = require('../../lib/redux/redux').combineReducers; var rootReducer = combineReducers({
- todos,
- counter
- }); var createStore = require('../../lib/redux/redux').createStore; var store = createStore(rootReducer); console.log(store.getState()) // {
- // counter: 0,
- // todos: []
- // }
- store.dispatch({
- type: 'ADD_TODO',
- text: 'Use Redux'
- }); // {
- // counter: 0,
- // todos: [ 'Use Redux' ]
- // }
新聞熱點
疑難解答