Redux是什麼
Redux 是 JavaScript 狀態容器,提供可預測化的狀態管理。
它認為:Web應用是一個狀態機,檢視與狀態一一對應。從架構層面來說,通常希望UI跟資料、邏輯分離,直觀體現就是:UI = render(state)
為什麼要用Redux
現在的Web應用涉及大量資料互動、非同步操作等,無疑都在增加前端的複雜性,需要維護的state也越來越多。而Redux就是試圖讓每個state變化都是可預測,將應用中所有的action與state統一管理。
Redux的三原則
- 單一資料來源 整個應用state應該只儲存在唯一一個的Store中。
- 保持狀態只是只讀 不能直接修改state,唯一能改變Store的state方法就是通過觸發一個action物件完成。
- 資料改變通過純函式完成 action改變state需要通過reducers。
Redux工作流程
在講Redux的工作流程之前,需瞭解幾個Redux相關的核心概念:
- Action:Action可以看成是應用發出的通知,表示State應該要發生變化了,Action的觸發可能是使用者對View層的操作也可能是伺服器的響應。
- Action Creator:如果有很多種Action,而每種Action都手寫的話顯得麻煩,所以用定義的Action Creator函式來生成Action。
- Dispatch:Action發出的唯一方法。
- Store:整個應用唯一儲存資料的地方。
- State:對Store中儲存資料生成某個時點資料快照,該資料集合叫做State。
- Reducer:Action只是描述了State應要發生變化,而Reducer做的是如何改變State。
具體工作流程: 使用者通過View(或伺服器響應)觸發Action,Dispatch方法將Action Creator函式生成的Action派發到Store,Store自動呼叫Reducer,並向它傳入當前State和Action,Reducer返回新的State,State一旦有變化,Store就會通過監聽函式來更新View。 借用一張圖來描述這一過程:
嚴格的單向資料流是 Redux 架構的設計核心。
幾個Redux核心概念例項
以從伺服器響應文章內容為例 Action
const LOAD_ARTICLES_DETAIL = 'LOAD_ARTICLES_DETAIL'
const LOAD_ARTICLES_DETAIL_SUCCESS = 'LOAD_ARTICLES_DETAIL_SUCCESS'
const LOAD_ARTICLES_DETAIL_ERROR = 'LOAD_ARTICLES_DETAIL_ERROR'
複製程式碼
Action Creator
export const loadArticlesDetail = () => ({
type: LOAD_ARTICLES_DETAIL
})
export const loadArticlesDetailSuccess = result => ({
type: LOAD_ARTICLES_DETAIL_SUCCESS,
result
})
export const loadArticlesDetailFailure = error => ({
type: LOAD_ARTICLES_DETAIL_ERROR,
error
})
複製程式碼
Store
const store = createStore(reducers)
複製程式碼
Reducer (previousState, action) => (newState)
export default (state = initalState, action) => {
switch (action.type) {
case LOAD_ARTICLES_DETAIL: {
return {
...state,
loading: true,
error: false
}
}
case LOAD_ARTICLES_DETAIL_SUCCESS: {
return {
...state,
loading: false,
error: false,
articlesDetail: action.result
}
}
case LOAD_ARTICLES_DETAIL_ERROR: {
return {
...state,
loading: false,
error: true
}
}
default:
return state
}
}
複製程式碼
深入到Redux的原始碼
Redux主要原始碼整體結構:
- 入口檔案 index.js
export {
createStore,
combineReducers,
bindActionCreators,
applyMiddleware,
compose
}
複製程式碼
這是入口檔案匯出的方法,也是Redux支援的方法,這些方法的實現在主工作流程檔案和輔助函式檔案,接下來看主工作流程。
- 主工作流程檔案 createStore.js
createStore方法主要是生成Store,看看它做了哪些事兒:
- getState方法返回了當前State
- subscribe方法傳入函式到監聽佇列和返回取消訂閱函式
- dispatch方法呼叫Reducer,按順序執行listener,返回Action 輔助原始碼檔案:
- applyMiddleware.js:用於增強Store
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
let dispatch = store.dispatch
let chain = []
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
複製程式碼
從原始碼上看,最後是返回了一個Store和一個被更新過的dispatch方法,實現了對Store的增強。
- bindActionCreators.js:
export default function bindActionCreators(actionCreators, dispatch) {
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch)
}
}
複製程式碼
使用dispatch把action creator都包裝起來,這樣可以直接呼叫它們。
- combineReducers.js:當應用比較大的時而拆分Reducer,但是傳入Store的Reducer必須是一個函式,所以這個方法的主要功能是用來合併多個Reducer。
- compose.js
compose這個方法,傳入的一系列函式,執行的最終結果是把各個函式串聯起來。export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args))) } 複製程式碼
總結:
- Redux 是 JavaScript 狀態容器,提供可預測化的狀態管理。
- 嚴格的單向資料流是 Redux 架構的設計核心。
- UI = render(state)