> 技术文档 > Redux 入门超详细指南

Redux 入门超详细指南

实习时突然遇到一个问题,一个页面中用到了将近 10 个组件,传参传来传去复杂得很,所以就有了这篇临时学习的 Redux 入门指南。

一、非常重要的 引言

在介绍什么是 Redux 前,我想先来介绍一下为什么我们要用到 Redux。这就不得不从 React 的本质上面说起。

1.1 React组件树的本质限制

在没有 Redux 之前,React 组件之间传递数据就像下面这样:

But,问题来了,为什么数据不能从 组件A 直接 传到 组件D,为什么中间要经过中转站呢?
注意,此处,React 基础非常好的同学可自动跳过 第一节 非常重要的引言(狗头)

1.1.1 React的数据流规则

React有一个 单向数据流 的核心原则:

  • 数据只能从 父组件 传递给 子组件

  • 兄弟组件之间 不能直接通信

  • 子组件 不能直接 向父组件传递数据(除了通过回调函数)

1.1.2 组件树结构示例

假设我们有这样的组件树结构:

App (根组件)├── Header│ └── UserInfo (组件A - 有用户数据)├── MainContent│ ├── Sidebar (组件B - 中转站)│ └── ProductList│ └── ProductCard (组件D - 需要用户数据)└── Footer

1.2 为什么不能直接从A传给D?

1.2.1 组件树层级关系

// 组件A和组件D在不同的分支上App├── Header│ └── UserInfo (A) ❌ 不能直接到达 ProductCard (D)└── MainContent └── ProductList └── ProductCard (D)

A和D不是直接的父子关系,React的props只能沿着父→子的路径传递

1.2.2  具体代码演示

// 这样是不可能的 - A不能直接传给Dfunction UserInfo() { // 组件A const userData = { name: \"张三\", id: 123 }; // 无法直接传递给ProductCard组件! //  // 这里访问不到ProductCard}function ProductCard() { // 组件D // 无法直接接收UserInfo的数据 // const userData = ???; // 从哪里获取?}

1.2.3 React的设计哲学

React被设计为:

  • 组件封装:每个组件只知道自己的直接子组件

  • 单向数据流:数据向下流动,事件向上冒泡

  • 可预测性:数据流向清晰,便于调试

二、为什么需要 Redux ?

2.1 什么是 Redux?

Redux 是一个用于 JavaScript 应用程序的状态管理库。想象一下,如果你的应用是一个大型商场,Redux 就像是商场的中央控制室,负责管理整个商场的所有信息(比如库存、顾客信息、营业状态等)。

在没有 Redux 之前,React 组件之间传递数据就像下面这样:

有了 Redux 之后,就像这样:

2.2 Redux 的核心概念

Redux 有三个核心概念,我们用一个简单的比喻来理解:

概念 比喻 作用 特点 Store 银行金库 存储所有数据 唯一、只读 Action 存取款单 描述要做什么 纯对象、有type Reducer 银行柜员 处理业务逻辑 纯函数、不可变

2.2.1 Store(仓库)

Store 就像一个大仓库,存放着应用的所有状态数据

// 创建一个简单的storeconst store = { count: 0, user: { name: \'张三\', age: 25 }}

2.2.2 Action(动作)

Action 就像一张说明书,告诉 Redux \"我想要做什么\"。

// 增加计数的actionconst incrementAction = { type: \'INCREMENT\' // 必须有type属性}// 设置用户名的actionconst setNameAction = { type: \'SET_NAME\', payload: \'李四\' // 携带数据}

2.2.3 Reducer(处理器)

Reducer 是一个函数,接收当前状态和 action,返回新的状态。

function counterReducer(state = { count: 0 }, action) { switch (action.type) { case \'INCREMENT\': return { count: state.count + 1 } case \'DECREMENT\': return { count: state.count - 1 } default: return state }}

2.3 Redux 的工作流程

2.3.1 工作流程图

2.3.2 简单的计数器例子

// 1. 定义初始状态const initialState = { count: 0}// 2. 创建 Reducerfunction counterReducer(state = initialState, action) { switch (action.type) { case \'INCREMENT\': return { count: state.count + 1 } case \'DECREMENT\': return { count: state.count - 1 } default: return state }}// 3. 创建 Storeconst store = Redux.createStore(counterReducer)// 4. 订阅状态变化store.subscribe(() => { console.log(\'当前计数:\', store.getState().count)})// 5. 发送 Actionstore.dispatch({ type: \'INCREMENT\' }) // 计数变为 1store.dispatch({ type: \'INCREMENT\' }) // 计数变为 2store.dispatch({ type: \'DECREMENT\' }) // 计数变为 1

2.4 Redux 三大原则

原则 说明 好处 违反后果 单一数据源 整个应用只有一个 Store 状态集中管理,易于调试 数据分散,难以追踪 状态只读 不能直接修改状态 保证数据流向可预测 状态混乱,难以回溯 纯函数修改 只能通过 Reducer 修改状态 副作用可控,易于测试 逻辑复杂,难以维护

2.5 Redux vs 其他状态管理方案

特性 传统React状态 Redux状态管理 数据传递 Props层层传递 组件直接访问Store 组件耦合 高度耦合,中间组件被污染 低耦合,组件独立 状态集中 分散在各个组件 集中在单一Store 调试难度 困难,难以追踪变化 简单,完整的操作历史 代码复杂度 随组件层级增加而增加 相对稳定 性能优化 需要手动优化 自动优化,精确更新 团队协作 容易产生冲突 标准化流程,易协作 测试难度 需要模拟大量props 独立测试Action和Reducer

2.6 Redux 的优缺点总结

 优点

  • 可预测性:状态变化完全可预测,便于调试

  • 集中管理:所有状态集中在一个地方

  • 时间旅行:可以回溯到任何历史状态

  • 强大的开发工具:Redux DevTools 提供强大的调试功能

  • 中间件支持:可以轻松添加日志、异步处理等功能

缺点

  • 学习曲线陡峭:概念较多,初学者需要时间理解

  • 代码量大:需要写很多样板代码

  • 过度工程:对于简单应用可能过于复杂

  • 性能开销:每次状态变化都会触发重新渲染

什么时候使用 Redux?