Redux 作為 JavaScript 應用的狀態管理庫,其技術架構與核心原理圍繞??可預測的狀態管理??設計,通過嚴格的單向數據流和函數式編程理念實現復雜應用的狀態控制。以下從設計理念、核心架構、工作流程、源碼實現等角度進行系統性剖析:
一、設計理念與原則
- ??單一數據源(Single Source of Truth)??
- 整個應用的狀態存儲在一個全局 Store 對象中,形成唯一的狀態樹(State Tree)。
- ??優勢??:簡化狀態共享和調試,避免分布式狀態導致的邏輯混亂。
- ??狀態只讀(State is Read-Only)??
- 狀態不可直接修改,唯一修改方式是 ??
dispatch(action)
??。Action 是描述狀態變化的普通對象,需包含type
屬性(如{ type: 'ADD_TODO', text: 'Learn Redux' }
)。 - ??目的??:確保狀態變更可追蹤,避免隱蔽的副作用。
- 狀態不可直接修改,唯一修改方式是 ??
- ??純函數更新(Changes via Pure Functions)?
- Reducer 是純函數,接收舊狀態和 Action,返回??新狀態??(而非修改舊狀態)。
- ??關鍵約束??:
- ??無副作用??:不修改輸入參數、不調用非純函數(如
Date.now()
)、不執行異步操作。 - ??冪等性??:相同輸入必得相同輸出。
- ??無副作用??:不修改輸入參數、不調用非純函數(如
二、核心架構解析
1. ??Store:狀態容器??
- 職責:
getState()
:獲取當前狀態。dispatch(action)
:觸發狀態更新。subscribe(listener)
:訂閱狀態變更事件。
- ??實現關鍵??:閉包管理狀態(
currentState
)和監聽器數組(currentListeners
)。
2. ??Action:狀態變更的描述??
- 本質:包含
type
的 JS 對象,可攜帶額外數據(如payload
)。 - ??Action Creator??:封裝創建 Action 的邏輯,提高代碼復用性。
3. ??Reducer:狀態變更的執行者??
-
函數簽名:
(state, action) => newState
。 -
??不可變更新??:必須返回新對象(而非修改原狀態)。
// 錯誤:直接修改原狀態 state.todos.push(action.payload); // 正確:返回新對象 return { ...state, todos: [...state.todos, action.payload] };
-
??組合性??:通過
combineReducers
拆分多個子 Reducer,分別管理狀態樹的不同部分。
4. ??Middleware:擴展 Dispatch 能力??
-
??攔截 Action??:在 Action 到達 Reducer 前執行額外邏輯(如異步請求、日志記錄)。
-
??中間件鏈??:通過函數嵌套實現(如
applyMiddleware(thunk, logger)
)。const thunkMiddleware = ({ dispatch }) => next => action => {if (typeof action === 'function') { return action(dispatch); // 處理函數型 Action(如 redux-thunk)}return next(action); // 傳遞普通 Action };
三、工作流程詳解
Redux 的數據流是嚴格的單向循環:
- ??觸發 Action??:用戶操作(如點擊)調用
dispatch(action)
。 - ??執行 Reducer??:Store 調用 Reducer,傳入當前狀態和 Action,生成新狀態。
- ??更新 Store??:新狀態替換舊狀態。
- ??通知訂閱者??:執行所有通過
subscribe()
注冊的監聽器(如觸發 React 組件重渲染)。 - ??視圖更新??:組件通過
getState()
獲取新狀態并更新 UI。
四、源碼核心實現
1. ??createStore
??:核心工廠函數
function createStore(reducer, preloadState) {let currentState = preloadState; // 閉包保存狀態let listeners = [];const getState = () => currentState;const subscribe = (listener) => {listeners.push(listener);return () => listeners.splice(listeners.indexOf(listener), 1); // 取消訂閱};const dispatch = (action) => {// 校驗 Action 為純對象if (Object.getPrototypeOf(action) !== Object.prototype) throw new Error('Action 必須是純對象');currentState = reducer(currentState, action); // 調用 Reducerlisteners.forEach(listener => listener()); // 通知訂閱者};dispatch({ type: '@@redux/INIT' }); // 初始化狀態return { dispatch, subscribe, getState };
}
2. ??combineReducers
??:合并多個 Reducer
export default function combineReducers(reducers) {const reducerKeys = Object.keys(reducers);return function combination(state = {}, action) {const nextState = {};reducerKeys.forEach(key => {const reducer = reducers[key];const prevStateForKey = state[key];nextState[key] = reducer(prevStateForKey, action); // 每個子 Reducer 獨立更新});return nextState;};
}
3. ??bindActionCreators
??:自動綁定 Dispatch
function bindActionCreator(actionCreator, dispatch) {return (...args) => dispatch(actionCreator(...args)); // 自動派發 Action
}
五、設計哲學與工程價值
- ??可預測性??:
- 狀態變更由純函數(Reducer)驅動,避免隱蔽的副作用。
- Action 日志 + 時間旅行調試(如 Redux DevTools)。
- ??解耦與復用??:
- 組件無需關心狀態來源,只需訂閱 Store 或通過
connect
(React-Redux)注入狀態。 - Reducer 可復用、可組合,適合模塊化開發。
- 組件無需關心狀態來源,只需訂閱 Store 或通過
- ??異步擴展??:
- 中間件機制支持
redux-thunk
(函數型 Action)、redux-saga
(生成器流程控制)等方案,分離副作用與核心邏輯。
- 中間件機制支持
六、適用場景與局限性
- ??適用??:
- 多組件共享復雜狀態(如用戶登錄態、全局配置)。
- 需要記錄/回放狀態變更(如撤銷重做)。
- ??不適用??:
- 簡單應用(引入 Redux 反而增加模板代碼)。
Redux 通過 ??Store 集中管理狀態??、??Action 描述變更意圖??、??Reducer 純函數更新狀態??的三元架構,實現狀態的可預測管理。其核心價值在于??嚴格的單向數據流??和??函數式編程約束??,為復雜應用提供可維護、可擴展的狀態管理方案。