导读:本期聚焦于大象创作的《Redux状态管理核心概念:Store、Action、Reducer分别是什么?》,敬请观看详情。Redux 把应用状态集中到一个全局 Store 中,状态的任何变化都必须经过固定的流程:视图层派发一个 Action,Reducer 根据 Action 的 type 字段计算新状态,Store 保存结果并通知订阅者。这套单向数据流看似增加了一些样板代码,但它让状态变化变得可追踪、可预测。Store 是唯一的数据源,Action 是描述发生了什么的普通对象,Reducer 是纯函数,接收旧状态和 Action 返回新状态。理解三者的职责边界是使用 Redux 的基础。本文通过最小可运行的 JavaScript 示例,分别阐述 Action 的定义、Reducer 的不可变更新以及 Store 的创建与订阅,帮助读者快速建立 Redux 核心概念的整体认识。掌握这些基础后,再学习中间件和异步流程会更加顺畅。

Redux 是一个可预测的状态容器,它把整个应用的状态集中到一个全局对象中,并规定了状态变更的唯一路径:视图触发 Action,Reducer 根据 Action 计算新状态,Store 保存新状态并通知订阅者。对于刚接触 Redux 的开发者来说,最需要理清的就是 Store、Action、Reducer 这三个概念各自的职责边界。本文从最基础的用法出发,用 JavaScript 代码展示它们是如何协作的。

Redux状态管理核心概念:Store、Action、Reducer分别是什么?

一、为什么 Redux 需要单一数据源和单向数据流

在传统的前端开发中,状态可能散落在各个组件的内部,组件之间通过层层传递回调或者直接操作全局变量来同步数据。当应用规模变大时,这种模式会让状态变化难以追踪,一个数据被多处修改,调试时往往需要同时查看多个文件才能搞清楚数据流。Redux 的核心思路就是把应用状态集中到一个 Store 中,任何组件都不能直接修改这个状态。

状态变更必须遵循单向数据流:组件只能通过 dispatch 一个 Action 来表达“发生了什么”,Reducer 负责根据这个 Action 计算出新的状态,Store 再把新状态保存起来并通知所有订阅者。这种约束牺牲了一部分灵活性,但换来了极强的可预测性。

二、Action:描述状态变化的意图

Action 本质上是一个普通的 JavaScript 对象,它必须包含一个 type 字段,用来描述这次操作的类型。除了 type 之外,Action 还可以携带额外的数据,通常放在 payload 字段中。例如,当用户添加一条待办事项时,可以定义一个 ADD_TODO 类型的 Action。

为了减少手写对象带来的错误,通常会创建一个 Action Creator 函数,它接收参数并返回一个符合规范的 Action 对象。这样做的好处是,类型字符串被封装在函数内部,修改时只需要改一处,同时调用方不需要关心 Action 的具体结构。

const ADD_TODO = 'ADD_TODO';

function addTodo(text) {
  return {
    type: ADD_TODO,
    payload: text
  };
}

Action 本身不直接操作状态,它只是描述了“我想添加一条待办”。真正的状态更新逻辑在 Reducer 中完成。把意图和实现分开是 Redux 设计的一个重要特点,它让开发者可以清晰地看到应用里到底发生了哪些操作。

三、Reducer:纯函数与不可变更新

Reducer 是一个纯函数,它接收旧的 state 和一个 action,然后根据 action.type 决定如何返回新的 state。纯函数有两个关键要求:一是不能产生副作用,例如不要修改传入的参数、不要发起网络请求;二是相同的输入必须得到相同的输出。正因为 Reducer 是纯函数,Redux 的状态变化才变得可预测。

Reducer 中最重要的一条规则是:永远不要直接修改旧的 state。如果 state 是一个对象,需要修改某个属性时,应该返回一个新的对象,可以使用对象展开运算符或者 Object.assign 来创建副本。如果 state 中包含数组,更新数组时也要返回一个新数组,例如使用 concat 或展开运算符,而不是直接调用 push

const initialState = {
  todos: []
};

function todoReducer(state = initialState, action) {
  switch (action.type) {
    case 'ADD_TODO':
      return {
        ...state,
        todos: state.todos.concat(action.payload)
      };
    default:
      return state;
  }
}

当 action.type 不匹配任何分支时,Reducer 必须返回原 state。如果 reducer 接收到的 state 是 undefined,Redux 会使用默认参数 state = initialState 来初始化状态。保持不可变更新可以让 Redux 的调试工具准确记录每一次状态变化,也便于后续的性能优化。

四、Store:连接 Action 与 Reducer 的枢纽

Store 是由 Redux 提供的 createStore 方法创建的,它接收一个 Reducer 作为参数。Store 保存了应用的完整状态树,并提供几个核心方法:getState 用来获取当前状态,dispatch 用来派发 Action,subscribe 用来订阅状态变化。在大多数情况下,一个应用只有一个 Store。

调用 dispatch 时,Store 会把当前的 state 和传入的 action 交给 Reducer,得到新的 state 后更新内部状态,并触发所有通过 subscribe 注册的监听函数。监听函数通常用来更新视图,在 React 应用中一般由 react-redux 库自动完成这一步,但理解整个流程非常有必要。

import { createStore } from 'redux';

const store = createStore(todoReducer);

store.subscribe(function() {
  console.log('当前状态:', store.getState());
});

store.dispatch(addTodo('学习 Redux'));
store.dispatch(addTodo('编写第一个示例'));

上面的代码创建了一个 Store,订阅了状态变化,然后派发了两个 Action。每次 dispatch 之后,控制台都会打印出最新的状态。可以看到,Store 本身并不承担状态计算的职责,它只负责调度和数据保存,真正的逻辑在 Reducer 中。

五、完整协作流程与最小示例

为了更直观地理解三者的关系,可以用一个完整的 JavaScript 示例把前面几部分组合起来。在这个示例中,我们不依赖任何额外的库,只使用 Redux 的核心 API 来演示状态的创建、变更和订阅。

const ADD_ITEM = 'ADD_ITEM';
const REMOVE_ITEM = 'REMOVE_ITEM';

function addItem(name) {
  return { type: ADD_ITEM, payload: name };
}

function removeItem(name) {
  return { type: REMOVE_ITEM, payload: name };
}

const initialItems = [];

function itemsReducer(state = initialItems, action) {
  switch (action.type) {
    case ADD_ITEM:
      return state.concat(action.payload);
    case REMOVE_ITEM:
      return state.filter(function(item) {
        return item !== action.payload;
      });
    default:
      return state;
  }
}

const store = createStore(itemsReducer);

store.subscribe(function() {
  console.log('最新状态:', store.getState());
});

store.dispatch(addItem('苹果'));
store.dispatch(addItem('香蕉'));
store.dispatch(removeItem('苹果'));

执行这段代码后,控制台会依次打印出三个状态:首先是只包含苹果的数组,然后是包含苹果和香蕉的数组,最后是只包含香蕉的数组。整个过程中没有一个地方直接修改了原数组,每次操作都返回了新的数组。这就是 Redux 最核心的工作方式。

六、常见认知误区与最佳实践

一个常见的误区是把 Action 和 Reducer 混为一谈。Action 只负责描述意图,Reducer 才负责计算新状态。如果在 Action 中直接操作了 Store,或者在 Action Creator 中执行了异步请求,就会破坏 Redux 的数据流。异步操作应该通过中间件来处理,例如 redux-thunkredux-saga,而不是放在 Action Creator 内部直接执行。

另一个值得注意的地方是 Reducer 的拆分。当应用状态越来越复杂时,把所有逻辑写在一个 Reducer 中会让函数体变得非常庞大。此时可以使用 combineReducers 把不同领域的 Reducer 组合起来,每个 Reducer 只负责管理状态树中的一个分支。这样既保持了单一数据源,又让代码结构清晰。初学者应该先熟练掌握 Store、Action、Reducer 的基础用法,再去接触中间件和状态拆分,这样能少走很多弯路。

Redux状态管理StoreAction Reducer修改时间:2026-08-27 05:51:21

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。