Redux是一個程序架構,源於Flux(Facebook提出的一種架構),然而,它不只能夠應用於React,還能夠應用於其餘任何框架中。值得一提的是,Redux的源代碼不多,可是他的邏輯拆分和函數式編程的設計思想是很是值得學習的。html
當一個JavaScript單頁應用變得愈來愈複雜時,咱們要處理的數據(model)也變得愈來愈龐大,隨之而來的是每一個數據的狀態(state)會變得難以維護。當一個model改變時,咱們可能要手動處理由此引起的其餘model的變化,更糟糕的是,其餘model變化可能又會引發另外一些model的變化,這樣產生連鎖反應。最後咱們很容易就會不記得model在何時以及如何發生改變。這正是Redux能夠解決的最大痛點之一—以統一的方式管理數據狀態。
統一的數據狀態管理體現爲如下2個方面:react
惟一改變 state 的方法就是觸發 action,action 是一個用於描述已發生事件的普通對象。編程
Actionredux
Action 是把數據從應用傳到 store 的有效載荷。它是 store 數據的惟一來源。直白的說,action就是一種消息類型,他告訴Redux是時候該作什麼了,並帶着相應的數據傳到Redux內部(即接下來介紹的Reducer)。
Action就是一個簡單的對象,其中必需要有一個type屬性,用來標誌動做類型(reducer以此判斷要執行的邏輯),其餘屬性用戶能夠自定義,但要儘可能簡單。如:segmentfault
{type: SET_ALL,index: 5}
Action Creator
Action Creator是一個用來自動生成Action的函數,這也是Redux函數式編程的一種體現。一般,咱們會按照業務邏輯或組件把相關的Action Creator放在一個文件中,形式以下:架構
export const SHOW_SLIDER = 'SHOW_SLIDER'; export const RIGHT_SLIDER = 'RIGHT_SLIDER'; export const showSliderAction = (index) => { return { type: SHOW_SLIDER, index }; } export const rightSliderAction = (length) => { return { type: RIGHT_SLIDER, length }; }
其中showSliderAction和rightSliderAction就是Action Creator。
因爲Action Creator的形式大致相同,咱們還能夠建立一個用來生成Action Creator的函數以進一步簡化。併發
export const makeCreateAction = (type, ...keys) => { return (...data) => { let action = {type}; keys.forEach((v,i) => action[v] = data[i]); return action; } } export const showSliderAction = makeCreateAction(SHOW_SLIDER, index); export const rightSliderAction = makeCreateAction(RIGHT_SLIDER, length);
Reducer
Reducer 指定了應用狀態的變化如何響應 actions 併發送到 store 的,action只是告訴Redux該幹什麼了,並無告訴他怎麼幹,而reducer就是根據action處理state如何改變的邏輯。
Reducer必須是一個純函數(緣由稍後解釋),他根據action處理state的更新,若是沒有更新或遇到未知action,則返回舊state;不然返回一個新state對象。注意:不能修改舊state,必須先拷貝一份state,再進行修改,也可使用Object.assign函數生成新的state。另外,state參數需先進行初始化。實例代碼以下:框架
//初始狀態 let initialState = {hiddenClass: 'g-hidden',currentIndex:0}; let sliderReducer = function (state = initialState, action) { switch(action.type){ case sliderAction.SHOW_SLIDER: return {hiddenClass: '',currentIndex:action.index}; case sliderAction.RIGHT_SLIDER: if(state.currentIndex == action.length-1){ return Object.assign({}, state, {currentIndex:0}); }else{ return Object.assign({}, state, {currentIndex:Number.parseInt(state.currentIndex)+1}); } default: return state; } } export default sliderReducer;
使用純函數的緣由:異步
首先,純函數的特色是: •函數的返回結果只依賴於它的參數。 •函數執行過程裏面沒有反作用。(不會對外界產生影響)
若是不使用純函數,即直接更改state值會怎麼樣呢?ide
… … case sliderAction.RIGHT_SLIDER: if(state.currentIndex == action.length-1){ state.currentIndex = 0; return state; } … …
以後會發現,不管state如何變化,UI都不會更新。如下是Redux的部分源碼:
經過查看Redux源碼得知,新舊state的比較只是對引用地址的比較,若是reducer只是返回舊state(即previousStateForKey)的更新,新state(nextStateForKey)實際上和舊state引用的都是同一塊內存地址,因此不管如何更改,新舊state始終保持相同。這就是爲何reducer必須是純函數的緣由。
Reducer拆分與合併:
Reducer 函數負責生成 State。因爲整個應用只有一個 State 對象,包含全部數據,對於大型應用來講,這個 State 必然十分龐大,致使 Reducer 函數也十分龐大。因此須要先對reducer進行拆分,拆分的原則能夠按業務邏輯進行劃分,若是是react的話,能夠直接和react的組件相對應進行劃分。
劃分好以後,能夠用Redux提供的combineReducers方法進行合併,十分方便。
import { combineReducers } from 'redux'; import photomainReducer from './photomainReducer'; import sortReducer from './sortReducer'; import sliderReducer from './photoSliderReducer'; export default combineReducers({ photomainReducer, sortReducer, sliderReducer });
Store
Store 是把Action、Reducer聯繫到一塊兒的對象。Store 有如下職責:
1.維持應用的 state; 2.提供 getState() 方法獲取 state; 3.提供 dispatch(action) 方法更新 state; 4.經過 subscribe(listener) 註冊監聽器; 5.經過 subscribe(listener) 返回的函數註銷監聽器。
(1) 建立store
Redux應用應該只有一個store,他提供了建立store的API—createStore(reducer, initState)。第一個參數爲一個reducer,能夠接受經過combineReducers合併後的reducer,第二個是可選參數,意思是能夠設置應用的初始state。
const store = createStore( indexPhotomainReducer, ); export default store;
(2)State
應用的state也應該只有一個,裏面包含了全部的應用數據。當須要獲取state的時候,須要使用store.getState()方法。
(3)store.dispatch(action)
UI更新state 的惟一途徑,經過dispatch方法發起action,喚起對應的reducer更新state。
(4)store. subscribe(listener)
經過此方法能夠設置監聽函數,一旦state發生變化,就會當即調用監聽函數(listener)。同時,subscribe的返回值(其實是一個unsubscribe函數)能夠解除監聽。如:
// 每次 state 更新時,打印日誌 // 注意 subscribe() 返回一個函數用來註銷監聽器 const unsubscribe = store.subscribe(() => console.log(store.getState()) ) // 中止監聽 state 更新 unsubscribe();
(1)首先,用戶發出 Action(如click事件)。
store.dispatch(SHOW_SLIDER)
(2) Store 自動調用 Reducer,而且傳入兩個參數:當前 State 和收到的 Action。 Reducer根據Action的type調用相應的分支, 返回新的 State 。
let initialState = {hiddenClass: 'g-hidden',currentIndex:0}; let sliderReducer = function (state = initialState, action) { switch(action.type){ case sliderAction.SHOW_SLIDER: return {hiddenClass: '',currentIndex:action.index}; default: return state; } }
(3) State 一旦有變化,Store 就會調用監聽函數。
store.subscribe(listener);
(4) listener能夠經過store.getState()獲得當前狀態。若是使用的是 React,這時能夠觸發從新渲染 View。
function listerner() { let newState = store.getState(); component.setState(newState); }
以上爲Redux的數據流動過程。
本篇到此告一段落,下一篇介紹Redux的異步實現。