站長阿川

站長阿川私房教材:
學 JavaScript 前端,帶作品集去面試!

站長精心設計,帶你實作 63 個小專案,得到作品集!

立即開始免費試讀!

深入理解 Redux:從手寫核心到現代實踐(附 RTK 銜接)

Redux 作為前端經典狀態管理庫,核心解決 “組件間狀態共享” 與 “狀態變更可追溯” 問題,適配大型 React 專案。這篇文章我透過結合手寫核心邏輯現代工具 RTK,拆解 Redux 原理,明晰 “底層原理” 與 “高效開發” 的協同路徑。

一、Redux 核心三要素:Action、Reducer、Store

Redux 遵循單向數據流,狀態變更需經 Action → Reducer → Store 流程,確保可預測性。

1. Action:操作描述的 “消息載體”

Action 是觸發狀態變更的 “入口”,本質是平面物件(需 isPlainObject 驗證),核心作用是描述 “發生了什麼操作”,可透過 payload 攜帶數據。

核心特性(結合手寫代碼)

  • 必須含 type 屬性:標識操作類型(如 INCREMENT),類型無強制約束(字串、Symbol 均可),大型專案建議單獨維護(如 actionTypes.js)避免硬編碼。
    示例:
// 基礎 Action 結構
const incrementAction = {
  type: "INCREMENT",
  payload: 1
};
  • Action 建立函數(Action Creator) :用純函數簡化 Action 生成,函數無副作用(不修改參數、無異步、不影響外部環境)。
    示例:
// 生成“增加計數”的 Action
const increment = (step) => ({
  type: "INCREMENT",
  payload: step
});
  • bindActionCreators:自動發送 Action
    手動創建 Action 需調用 store.dispatch(action) 觸發變更,bindActionCreators 可增強 Action Creator,使其創建後自動發送,簡化代碼。
    核心實現(手寫邏輯):
function getAutodisPatchActionCreator(actionCreator, dispatch) {
  return (...args) => {
    const action = actionCreator(...args); 
    dispatch(action); 
  };
}

export default function bindActionCreators(actionCreators, dispatch) {
  if (typeof actionCreators === 'function') {
    return getAutodisPatchActionCreator(actionCreators, dispatch);
  }
  const result = {};
  for (const key in actionCreators) {
    const creator = actionCreators[key];
    if (typeof creator === 'function') {
      result[key] = getAutodisPatchActionCreator(creator, dispatch);
    }
  }
  return result;
}

2. Reducer:狀態計算的 “純函數”

Reducer 是 Redux 的 “狀態計算核心”,接收當前 state 和 Action,返回新狀態(不可修改原狀態),決定 “如何根據操作變更狀態”。

核心特性(結合手寫代碼)

  • 必須是純函數:保障 Redux 可預測性,要求:

    • 不修改入參 stateaction
    • 無異步操作(如定時器、介面請求);
    • 不影響外部環境(如修改全局變數、操作 DOM)。
      優勢:純函數便於測試、可還原狀態,且能優化 React 組件渲染(避免不必要重繪)。
  • 初始化狀態的技巧
    創建 Store 時,Redux 自動發送初始化 Action(類型為 @@redux/INIT + 隨機字串,由 ActionTypes.INIT() 生成),此時 Reducer 接收 state = undefined,可透過參數預設值初始化狀態:

// 計數狀態管理示例
function countReducer(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + action.payload; 
    case "DECREMENT":
      return state - action.payload;
    default:
      return state; 
  }
}
  • combineReducers:拆分複雜 Reducer
    大型專案狀態結構複雜(如 “使用者資訊”“購物車”),需按 “狀態模組” 拆分 Reducer,再用 combineReducers 合併為根 Reducer
    核心實現(手寫邏輯):
export default function combineReducers(reducers) {
  validateReducers(reducers); 

  return function (state = {}, action) {
    const newState = {};
    for (const key in reducers) {
      if (reducers.hasOwnProperty(key)) {
        const subReducer = reducers[key];
        newState[key] = subReducer(state[key], action); 
      }
    }
    return newState; 
  };
}

示例(合併 “使用者” 與 “計數” 模組):

const rootReducer = combineReducers({
  user: userReducer, 
  count: countReducer 
});
// Store 狀態結構:{ user: {...}, count: 0 }

3. Store:狀態的 “統一容器”

Store 是 Redux 中 “唯一的狀態容器”,透過 createStore(reducer) 創建,封裝狀態存儲、發送 Action、監聽狀態變化的核心能力。

核心方法(手寫實現)

  • getState():獲取當前狀態
    直接返回 Store 內部保存的 currentState,是組件獲取狀態的唯一途徑:
function getState() {
  return currentState; 
}
  • dispatch(action):觸發狀態變更
    唯一能修改狀態的方法,流程:
    ① 驗證 Action(必須是平面物件,且含 type);
    ② 調用 Reducer,傳入當前狀態和 Action,計算新狀態;
    ③ 執行所有監聽器(listeners),通知狀態變更。
    核心代碼:
function dispatch(action) {
  if (!isPlainObject(action)) {
    throw new TypeError("action must be a plain object");
  }
  if (action.type === undefined) {
    throw new TypeError("action must has a property of type");
  }

  currentState = currentReducer(currentState, action); 

  for (const listener of listeners) {
    listener(); 
  }
}
  • subscribe(listener):監聽狀態變化
    註冊 “狀態變更監聽器”(無參函數),dispatch 觸發後執行所有監聽器;返回 “取消監聽” 函數,避免記憶體洩漏。
    核心代碼:
function subscribe(listener) {
  listeners.push(listener); 
  let isRemoved = false;

  return function () {
    if (isRemoved) return;
    const index = listeners.indexOf(listener);
    listeners.splice(index, 1); 
    isRemoved = true;
  };
}
  • Store 初始化
    創建 Store 時,自動發送初始化 ActionActionTypes.INIT()),觸發 Reducer 執行,透過參數預設值完成狀態初始化(無需手動傳預設狀態)。

二、Redux 工具函數與中介軟體

1. 工具函數:保障核心邏輯合法性

  • isPlainObject(obj) :驗證平面物件(__proto__ 指向 Object.prototype),避免非標準物件(如陣列、類實例)導致邏輯異常。
export default function isPlainObject(obj) {
  if (typeof obj !== "object") return false;
  return Object.getPrototypeOf(obj) === Object.prototype;
}
  • ActionTypes:生成隨機初始化 Action 類型(如 @@redux/INIT + 隨機字串),避免與業務 Action 衝突。
function getRandom(length) {
  return Math.random().toString(36).slice(2, length + 2).split("").join(".");
}

export default {
  INIT() { return `@@redux/INIT${getRandom(6)}`; },
  UNKNOWN() { return `@@redux/PROBE_UNKNOWN_ACTION${getRandom(6)}`; }
};

2. 中介軟體:增強 dispatch 能力

Redux 核心僅支持同步 Action,處理異步操作(如介面請求)需透過中介軟體擴展 dispatch 功能。

中介軟體本質是 “函數鏈”,在 dispatch 觸發 Action 後、Reducer 執行前,插入自定義邏輯(如異步請求、日誌、錯誤捕獲)。常見中介軟體:

  • redux-thunk:支持函數式 Action(Action 可返回函數,內部執行異步操作);
  • redux-saga:用 Generator 管理複雜異步流程(如介面重試、競態處理)。

核心原理:中介軟體包裝 store.dispatch,支持非標準 Action(如函數、Promise),待異步完成後,發送真正的 “同步 Action” 觸發狀態變更。

三、從手寫 Redux 到 RTK:現代開發的演進

現代開發中,Redux 官方推出 Redux Toolkit(RTK) ,封裝 createSlice(合併 Action 與 Reducer)、configureStore(簡化 Store 創建,內置中介軟體)等工具,大幅減少重複代碼(無需手動寫 combineReducersbindActionCreators),已成為 Redux 開發的推薦方案

手寫核心 vs RTK:定位與價值

  • 手寫核心:並非替代 RTK,而是為了深入理解 Redux 底層邏輯。掌握核心原理後,能更靈活應對 RTK 封裝的 “黑盒場景”(如自定義中介軟體、調試複雜狀態流)。
  • RTK:基於 Redux 核心邏輯的高效工具,讓開發更簡潔(如 createSlice 自動生成 Action 與 Reducer),適合快速迭代的專案。

RTK 關鍵工具示例

  • createSlice:合併 Action 類型、Reducer、Action Creator,自動生成 Action(如 increment)。
import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: 0,
  reducers: {
    increment: (state, action) => state + action.payload,
    decrement: (state, action) => state - action.payload,
  },
});

// 自動生成 Action Creator:counterSlice.actions.increment
  • configureStore:簡化 Store 創建,內置 redux-thunkredux-devtools 等中介軟體。
import { configureStore } from '@reduxjs/toolkit';

const store = configureStore({
  reducer: rootReducer, 
});

四、Redux 工作流程與核心價值

1. 完整流程(手寫與 RTK 通用)

  1. 組件調用 Action Creator(或 RTK 的 slice.actions)觸發 Action;
  2. dispatch 傳遞 Action 至 Reducer;
  3. Reducer 計算新狀態,更新 Store;
  4. 監聽器(如 React 組件的重新渲染邏輯)觸發組件更新,讀取新狀態(store.getState())。

2. 核心價值

Redux 透過分離 Action、Reducer、Store,讓狀態變更可追溯、可測試,尤其適配大型專案的複雜狀態管理。

  • 手寫核心:是理解 Redux 設計思想的 “最佳路徑”,掌握後能精確定位狀態問題;
  • RTK:是高效開發的 “助推器”,讓 Redux 從 “繁瑣配置” 轉向 “簡潔實踐”。

五、總結

Redux 的核心價值在於規範狀態管理流程,手寫實現揭示其 “簡潔而嚴謹” 的邏輯(純函數、單向數據流);RTK 則是站在 Redux 肩膀上的 “現代工具”,讓開發更高效。

對於我們開發者而言:

  • 新手可先透過手寫核心理解原理,再遷移到 RTK 簡化開發;
  • 進階者需兼顧 “底層邏輯” 與 “工具應用”,讓 Redux 真正服務於專案穩定性與可維護性。

二者相輔相成,共同構建前端狀態管理的 “清晰脈絡”。


如果您覺得這篇文章對您有幫助,歡迎按讚和收藏,大家的支持是我繼續創作優質內容的動力🌹🌹🌹也希望您能在😉😉😉我的首頁 😉😉😉找到更多對您有幫助的內容。

  • 致敬每一位趕路人

原文出處:https://juejin.cn/post/7543451693477609518


共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
站長阿川

站長阿川私房教材:
學 JavaScript 前端,帶作品集去面試!

站長精心設計,帶你實作 63 個小專案,得到作品集!

立即開始免費試讀!