揭秘 Redux Toolkit:用原生 JavaScript 一窥内部

发布: (2026年2月11日 GMT+8 20:32)
11 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的完整文本内容,我将按照要求将其翻译为简体中文,并保留原始的格式、Markdown 语法以及技术术语。谢谢!

实践探索 Redux Toolkit 如何在基于核心 JavaScript 和 Redux 原则的基础上简化状态管理

介绍

嗨!如果你曾在真实项目中与 Redux 纠缠过,你一定知道它常常像一只充斥着样板代码的怪兽——动作四处飞舞,reducer 像杂草一样蔓延。这时 Redux Toolkit 就像友好的副手出现,削减冗余,让你专注于真正重要的事:构建功能。

在本指南中,我们将揭开 Redux Toolkit 实际内部工作原理的面纱,一切都基于原生 JavaScript 和 Redux 基础。你将了解到它并非魔法,而是聪明的抽象,使你的代码更简洁、更易维护。阅读完本指南后,你将能够:

  • 识别驱动它的 JavaScript 模式
  • 自信地排查问题
  • 在需要时自行实现简化

无论你是 Redux 新手还是经验丰富的老手,这都将提升你的思维模型。让我们开始吧!

目录

  1. 基础:Redux Toolkit 是什么(以及不是)
  2. 实战示例:构建一个简单的 Slice
  3. 可视化直觉:底层数据流
  4. 真实案例:管理异步数据
  5. 高级技巧:自定义与扩展
  6. 常见错误:避免的陷阱
  7. 总结

基础:Redux Toolkit 是什么(以及不是什麼)

先从简单的说起。Redux Toolkit 并不是对 Redux 的完整重写;它是 基于 Redux 构建的一套实用工具,旨在减少样板代码并强制最佳实践。其核心全部是 JavaScript:函数、对象以及不可变更新。

为什么这很重要?

在原生 Redux 中,你需要手动:

  • 创建 action‑type 字符串
  • 编写 action‑creator 函数
  • switch 语句构建 reducer

这种做法容易出错且冗长。Redux Toolkit 将这些步骤封装在更高级的 API(如 createSlice)中,底层为你生成样板代码。

createSlice 的作用

createSlice 接收一个包含 nameinitialStatereducers 的对象。它返回一个 slice 对象,其中包含:

  • Action 创建器(slice.actions
  • reducer 函数(slice.reducer

在内部它会:

  1. 生成类似 ${sliceName}/${reducerName} 的 action 类型
  2. 创建返回 { type, payload } 对象的 action‑creator 函数
  3. 构建一个 reducer,将这些类型映射到提供的 reducer 函数,并使用 Immer 允许“变异”语法,同时保持更新的不可变性。

下面是一个 概念性(简化版)createSlice 的实现——并非实际源码

function createSlice({ name, initialState, reducers }) {
  const actions = {};
  const reducerCases = {};

  for (const [reducerName, reducerFn] of Object.entries(reducers)) {
    const type = `${name}/${reducerName}`;
    actions[reducerName] = (payload) => ({ type, payload });
    reducerCases[type] = reducerFn;
  }

  const reducer = (state = initialState, action) => {
    const handler = reducerCases[action.type];
    return handler ? handler(state, action) : state;
  };

  return { reducer, actions };
}

提示: 初学者常犯的一个错误是认为 Redux Toolkit “会直接变更”状态。事实并非如此——Immer 会拦截看似可变的代码并生成不可变的更新。

始终记住: Redux Toolkit 强制执行 Redux 的不可变性规则,以防止 bug。

Source:

实践示例:构建一个简单的 Slice

好了,你已经掌握了理论——现在来实际操作一下。假设你在构建一个 todo 应用。在原生 Redux 中,你需要为 action 类型、action 创建函数和 reducer 分别创建文件。而使用 Toolkit,只需一次 createSlice 调用即可。

安装

npm install @reduxjs/toolkit

(假设你在一个 React 项目中。)

定义 slice

import { createSlice } from '@reduxjs/toolkit';

const todosSlice = createSlice({
  name: 'todos',
  initialState: [],
  reducers: {
    addTodo: (state, action) => {
      // 看起来是可变的,但 Immer 会处理它!
      state.push(action.payload);
    },
    toggleTodo: (state, action) => {
      const todo = state.find(t => t.id === action.payload);
      if (todo) {
        todo.completed = !todo.completed;
      }
    },
  },
});

export const { addTodo, toggleTodo } = todosSlice.actions;
export default todosSlice.reducer;

设置 store

configureStore 是对 Redux 的 createStore 的轻量封装。它会添加诸如 Redux Thunk 中间件和 DevTools 集成等实用默认配置。

import { configureStore } from '@reduxjs/toolkit';
import todosReducer from './todosSlice';

export const store = configureStore({
  reducer: {
    todos: todosReducer,
  },
});

在组件中使用 slice

import { useSelector, useDispatch } from 'react-redux';
import { addTodo } from './todosSlice';

function TodoList() {
  const todos = useSelector(state => state.todos);
  const dispatch = useDispatch();

  return (
    <div>
      {todos.map(todo => (
        <li key={todo.id}>{todo.text}</li>
      ))}
      <button
        onClick={() =>
          dispatch(
            addTodo({ id: Date.now(), text: 'New todo', completed: false })
          )
        }
      >
        Add Todo
      </button>
    </div>
  );
}

addTodo 被 dispatch 时,Redux Toolkit 会生成如下的 action:

{ "type": "todos/addTodo", "payload": { "id": 123, "text": "New todo" } }

得益于 Immer,reducer 能以不可变的方式处理它。

专业提示: 始终同时导出 actions reducer。忘记导出 actions 是导致 “undefined action” 错误的常见原因。

Source:

可视化直觉:底层数据流

图片有帮助,对吧?下面是 Redux Toolkit 中单向数据流的思维模型:

Component


dispatch(action) ──► Store


          reducers (with Immer) → new state


               store notifies subscribers


               Component re‑renders
  • Dispatch(分发): dispatch(addTodo(payload)) 只是一条普通的函数调用,返回一个 action 对象。
  • Store(存储): Store 将该 action 通过 reducer 链进行处理。
  • Reducers(简化器): Toolkit 的 reducer 接收一个 draft 状态(由 Immer 提供),你可以对其“变更”。Immer 记录这些更改并生成一个新的不可变状态。
  • Subscribers(订阅者): useSelector(或 connect)会订阅 store;当它关注的状态片段发生变化时,组件会重新渲染。

实际案例:管理异步数据

(章节占位符 – 在此添加您的 async‑thunk 示例。)

高级技巧:自定义和扩展

(章节占位符 – 讨论 createAsyncThunk、中间件、自定义 reducers 等。)

常见错误:需避免的陷阱

  1. 假设 Toolkit 会直接修改状态 – 请记住,实际的工作是由 Immer 完成的。
  2. 忘记导出 actions – 会导致 “undefined is not a function” 错误。
  3. 将 Toolkit 与手动 switch reducer 混用 – 虽然可以运行,但违背了抽象的初衷。
  4. 在 reducer 之外修改状态 – 切勿直接修改 store 的状态;必须通过 actions 进行。

完成总结

Redux Toolkit 并非魔法;它是一套设计良好的实用工具,依赖于普通的 JavaScript 模式——对象遍历、模板字面量和函数组合——同时为你处理 Redux 中繁琐的部分。了解其内部工作原理后,你可以:

  • 编写更简洁、更易维护的代码
  • 自信地进行调试
  • 在需要时扩展或甚至自行实现抽象层

编码愉快! 🚀

Redux Toolkit 工作原理(内部实现)

action creator 返回一个对象时,中间件(例如 Thunk)会检查该 action 是否为异步的。如果是,中间件会处理异步流程;否则,action 会直接传递给根 reducer,根 reducer 再委派给相应的 slice reducer。

可以把它想象成一个 JavaScript 事件总线:store 是一个提供三个核心方法的对象:

  • dispatch – 将 action 通过中间件链发送。
  • subscribe – 注册监听器,在每次状态变化后运行。
  • getState – 返回当前状态。

configureStore 用来创建这个 store,并添加调试、DevTools 集成等增强功能。

直观可视化(流程图)

  1. Action 被分发 → 通过 中间件链(一个函数数组,每个函数调用 next)。
  2. Reducer 被调用 → 使用不可变更新(Object.assign、展开运算符或 Immer)来更新状态。
  3. 订阅者收到通知 → React‑Redux 的 useSelector 钩子触发组件重新渲染。

简化版 JavaScript 模拟 Store 的 Dispatch 循环

function createSimpleStore(reducer, initialState) {
  let state = initialState;
  const listeners = [];

  function dispatch(action) {
    // Immutable update here
    state = reducer(state, action);
    listeners.forEach(listener => listener());
  }

  function subscribe(listener) {
    listeners.push(listener);
    // Return an unsubscribe function
    return () => listeners.splice(listeners.indexOf(listener), 1);
  }

  function getState() {
    return state;
  }

  return { dispatch, subscribe, getState };
}

提示框: 为了提升可访问性,请确保应用的状态变化不会破坏键盘导航。对依赖 Redux 状态的 toast 或 modal 使用 ARIA live 区域。这类小的用户体验改进并不会被 Redux Toolkit 自动处理。

0 浏览
Back to Blog

相关文章

阅读更多 »

📦Redux 是什么?

如果你正在学习前端开发,尤其是使用 React,你可能听说过 Redux。它起初可能会让人感到困惑,但核心思想很简单……

Server Components 不是 SSR!

SSR 与 React Server Components 在开发者世界中,React Server Components(RSC)常被误认为只是另一种 Server‑Side Rendering(SSR)的形式。虽然两者……