Redux 状态管理

Redux 是一个可预测的状态管理容器,用于 JavaScript 应用。它帮助你编写行为一致、易于测试、在不同环境(客户端、服务器、原生应用)中运行的应用。

📑 快速导航

🎯 学习建议

如果你是新手,建议按照以下顺序学习:

  1. 先学 Redux 基础(本文档)- 理解同步状态管理
  2. 再学 Redux-SagaRedux-Saga 文档)- 处理异步操作
  3. 参考学习路径完整学习路径)- 系统掌握

💡 提示:Redux 只能处理同步操作,异步操作需要使用 Redux-Saga 或 Redux-Thunk。建议学习 Redux-Saga,功能更强大。


一、为什么需要 Redux?

问题场景

在大型 React 应用中,组件之间需要共享状态。如果通过 props 一层层传递,会导致:

  • Props 钻取:中间组件不需要这些 props,却要传递
  • 状态管理混乱:状态分散在各个组件中,难以追踪和调试
  • 组件耦合:组件之间相互依赖,难以维护

Redux 的解决方案

Redux 将应用的状态集中管理在一个 Store(仓库)中,所有组件都可以直接访问和修改状态,而不需要通过 props 传递。


二、核心概念(通俗理解)

1. Store(仓库)

就像是一个全局的数据库,存储整个应用的状态。

// Store 就像一个对象
const store = {
  count: 0,
  user: { name: '张三', age: 25 },
  todos: []
}

2. Action(动作)

描述”发生了什么”的普通对象,就像是一个”事件通知”。

// Action 必须有一个 type 字段,描述动作类型
const action = {
  type: 'INCREMENT',  // 动作类型:增加
  payload: 1          // 可选:携带的数据
}

3. Reducer(处理器)

纯函数,根据 Action 来更新 State,就像是一个”状态转换器”。

// Reducer 接收当前 state 和 action,返回新的 state
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
  }
}

4. Dispatch(派发)

发送 Action 的方法,组件通过 dispatch 来触发状态更新。

// 组件调用 dispatch 发送 action
dispatch({ type: 'INCREMENT' })

三、数据流向(单向数据流)

┌─────────┐
│ 组件     │
│ (UI)    │
└────┬────┘
     │ dispatch(action)
     │
     ▼
┌─────────┐
│  Store  │
│         │
│  State  │ ◄─────── Reducer ──────── Action
│         │
└────┬────┘
     │ subscribe
     │
     ▼
┌─────────┐
│ 组件     │
│ (UI)    │
└─────────┘

流程说明:

  1. 用户操作 → 组件调用 dispatch(action)
  2. Store 接收 action → 调用 reducer(state, action)
  3. Reducer 返回新 state → Store 更新
  4. Store 通知所有订阅的组件 → 组件重新渲染

四、最小闭环 Demo

环境准备

npm install redux react-redux

完整代码示例

1. 创建 Store 和 Reducer

// store/counterReducer.js
const initialState = {
  count: 0
}
 
function counterReducer(state = initialState, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 }
    case 'DECREMENT':
      return { ...state, count: state.count - 1 }
    case 'RESET':
      return { ...state, count: 0 }
    default:
      return state
  }
}
 
export default counterReducer
// store/index.js
import { createStore } from 'redux'
import counterReducer from './counterReducer'
 
// 创建 Store
const store = createStore(counterReducer)
 
export default store

2. 创建 React 组件

// components/Counter.jsx
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
 
function Counter() {
  // 从 Store 中获取状态
  const count = useSelector(state => state.count)
  
  // 获取 dispatch 方法
  const dispatch = useDispatch()
 
  return (
    <div>
      <h2>计数器: {count}</h2>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>
        +1
      </button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>
        -1
      </button>
      <button onClick={() => dispatch({ type: 'RESET' })}>
        重置
      </button>
    </div>
  )
}
 
export default Counter

3. 连接 Redux 和 React

// App.jsx
import React from 'react'
import { Provider } from 'react-redux'
import store from './store'
import Counter from './components/Counter'
 
function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  )
}
 
export default App

4. 入口文件

// index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
 
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App />)

五、核心原则

1. 单一数据源(Single Source of Truth)

整个应用的状态存储在一个 Store 中,便于调试和管理。

2. State 是只读的(State is Read-Only)

不能直接修改 State,只能通过 dispatch action 来更新。

// ❌ 错误:直接修改 state
state.count = 10
 
// ✅ 正确:通过 dispatch action
dispatch({ type: 'INCREMENT' })

3. 使用纯函数进行修改(Changes are Made with Pure Functions)

Reducer 必须是纯函数:

  • 相同输入 → 相同输出
  • 不产生副作用(不修改外部变量、不发起网络请求等)
  • 不修改原 state,返回新 state
// ✅ 正确:纯函数
function reducer(state, action) {
  return { ...state, count: state.count + 1 }
}
 
// ❌ 错误:修改了原 state
function reducer(state, action) {
  state.count++  // 修改了原对象
  return state
}

六、最佳实践

1. Action Creator(动作创建函数)

将 action 的创建逻辑封装成函数,便于复用和维护。

// actions/counterActions.js
export const increment = () => ({
  type: 'INCREMENT'
})
 
export const decrement = () => ({
  type: 'DECREMENT'
})
 
export const reset = () => ({
  type: 'RESET'
})
 
export const incrementByAmount = (amount) => ({
  type: 'INCREMENT_BY_AMOUNT',
  payload: amount
})

使用:

import { increment, decrement } from './actions/counterActions'
 
dispatch(increment())
dispatch(decrement())

2. 多个 Reducer 合并(combineReducers)

当应用状态复杂时,可以拆分为多个 reducer,然后合并。

// store/index.js
import { createStore, combineReducers } from 'redux'
import counterReducer from './counterReducer'
import userReducer from './userReducer'
 
const rootReducer = combineReducers({
  counter: counterReducer,
  user: userReducer
})
 
const store = createStore(rootReducer)
 
// 使用
const count = useSelector(state => state.counter.count)
const userName = useSelector(state => state.user.name)

3. Redux DevTools

安装 Redux DevTools 浏览器扩展,可以:

  • 查看所有 action 和 state 变化
  • 时间旅行调试(撤销/重做)
  • 导出和导入 state
// store/index.js
const store = createStore(
  rootReducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)

七、常见问题

Q1: Redux 和 Context API 有什么区别?

特性ReduxContext API
适用场景大型应用,复杂状态管理小型应用,简单状态共享
性能精确订阅,只更新需要的组件可能触发所有消费组件更新
调试强大的 DevTools,时间旅行相对简单
学习曲线较陡较平缓

Q2: 什么时候应该使用 Redux?

适合使用 Redux:

  • 应用状态需要全局共享
  • 状态变化逻辑复杂
  • 需要时间旅行调试
  • 需要状态持久化

不适合使用 Redux:

  • 简单的局部状态可以用 useState
  • 组件间简单通信可以用 Context API
  • 不需要复杂的状态管理

Q3: 如何组织 Redux 代码结构?

推荐的文件结构:

src/
├── store/
│   ├── index.js          # Store 配置
│   ├── rootReducer.js    # 根 Reducer
│   └── slices/           # 功能模块
│       ├── counterSlice.js
│       └── userSlice.js
├── actions/              # Action Creators(可选)
│   └── counterActions.js
└── components/
    └── Counter.jsx

八、Redux 的局限性(为什么需要 Redux-Saga)

Redux 只能处理同步操作

Redux 的 Reducer 必须是纯函数,这意味着:

  • ✅ 可以:根据 action 计算新的 state
  • ❌ 不可以:执行异步操作(API 调用、定时器等)
  • ❌ 不可以:产生副作用(修改外部变量、DOM 操作等)

实际应用中的异步需求

但在实际项目中,我们经常需要:

  • 调用 API 获取数据
  • 处理文件上传
  • 管理 WebSocket 连接
  • 执行定时任务(轮询)

解决方案:Redux-Saga

当需要处理异步操作时,推荐使用 Redux-Saga

  • ✅ 基于 Generator 函数,代码更优雅
  • ✅ 声明式 API,易于测试
  • ✅ 强大的并发控制
  • ✅ 支持任务取消

👉 下一步学习Redux-Saga 完整文档


九、总结

核心要点

  1. Store:存放全局状态
  2. Action:描述状态变化
  3. Reducer:纯函数,根据 action 更新 state
  4. Dispatch:发送 action 的方法

数据流向

用户操作 → dispatch(action) → reducer → 新 state → 组件更新

三个原则

  1. 单一数据源
  2. State 只读
  3. 纯函数修改

参考资料


相关文档


redux 状态管理 react 前端框架