跳到主要内容

工作流

React-Redux 的工作流是单向数据流的典型实现,核心围绕 Store(状态容器)Reducer(状态计算逻辑)Action(状态变更指令)React 组件(视图层) 的协作展开。

一、初始状态初始化

Redux 应用的核心是一个 单一 Store(通过 createStoreconfigureStore 创建),它存储整个应用的状态树。

  • 初始化时,Redux 会调用 Root Reducer(通常由 combineReducers 合并多个子 Reducer),传入初始状态(initialState),生成 Store 的初始状态
  • React 组件通过 Provider 组件(来自 React-Redux)包裹,将 Store 注入到组件树中,使所有子组件可访问

二、组件触发 Action (事件起点)

用户在界面进行交互(如点击按钮、输入表单)时, React 组件会 派发(Dispatch)一个 Action,这是状态变更的起点。

关键角色

  • Action: 一个普通 JavaScript 对象,必须包含 type 字段(标识操作类型),可选携带 payload (数据负载)
  • Action Creator: 函数,用于生成 Action 对象(可选,但推荐使用,简化重复代码)
// 创建 Action
const increment = amount => ({ type: 'INCREMENT', payload: amount });

// 在组件中触发
dispatch(increment(1));

组件中的触发方式

  • 类组件:通过 connect 高阶组件注入 dispatch 方法,直接调用 this.props.dispatch(increment(1))
  • 函数组件:通过 useDispatchHook 获取 dispatch 函数,调用 dispatch(increment(1))

三、 Reducer 计算新状态(纯函数处理)

Store 接收到 dispatch(action) 后,会将当前状态(currentState )和 Action 传递给 Root Reducer,由 Reducer 计算新状态。

Reducer 的核心规则:

  • 纯函数:必须返回新的状态对象(不可修改原状态),无副作用(不调用 API、不修改外部变量)
  • 状态不可变:通过复制原状态并修改副本的方式生成新状态(如使用展开运算符 ... 或 immer 库)
//  初始状态
const initialState = { count: 0 };

// Counter Reducer
function counterReducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + action.payload }; // 返回新状态
case 'DECREMENT':
return { ...state, count: state.count - action.payload };
default:
return state; // 未匹配的 Action 返回原状态
}
}

多 Reducer 合并:

复杂应用通常拆分为多个子 Reducer (如 userReducercartReducer),通过 combineReducers 合并成为 Root Reducer:

import { combineReducers } from 'redux';

const rootReducer = combineReducers({
user: userReducer,
cart: cartReducer,
// ... 其他 Reducer
});

四、 更新 Store 状态

Reducer 返回新状态后, Store 会:

  • 替换当前状态为新的状态树(currentState = newState
  • 触发订阅通知:调用所有通过 store.subscribe(listener) 注册的监听函数(React-Redux 会自动处理这部分)

五、 组件订阅并重新渲染(视图更新)

React 组件通过 订阅 Store 状态变化来感知更新,并重新渲染以后反映最新状态。

订阅的两种方式

  • 类组件connect 高阶组件
  • 函数组件:useSelectorHook 使用

1. 类组件: connect 高阶组件注入

connect(mapStateToProps, mapDispatchToProps)(myComponent) 会将组件与 Store 连接:

  • mapStateToProps:从 Store 状态中提取需要的属性(state => ({count: state.counter.count})),当相关状态变化时,组件重新渲染
  • mapDispatchToProps:将 Action Creator 映射为组件的 dispatch 方法(可选,也可以手动调用 dispatch

2. 函数组件:useSelectorHook

useSelector(selector) 允许函数组件直接从 Store 中选择状态:

  • selector 是一个函数(state => state.counter.count),返回组件需要的状态片段
  • selector 返回的值变化时,组件重新渲染(默认浅比较,可通过第二参数自定义比较逻辑)

六、异步 Action (如 API 请求)

实际开发中常需处理异步请求(如请求数据)。此时需借助中间件(Middleware),例如 redux-thunkredux-saga

  • 异步 Action Creator 返回一个函数(而非对象),通过 dispatch 分阶段派发同步 Action (如 LOADING、SUCCESS/FAILURE)
const fetchUser = useId => async dispatch => {
dispatch({ type: 'USER_LOADING' }); // 开始加载

try {
const response = await api.getUser(userId);
dispatch({ type: 'USER_SUCCESS', payload: response.data }); // 加载成功
} catch (error) {
dispatch({ type: 'USER_FAILURE', payload: error.message }); // 加载失败
}
};

七、 完整的示例

Todo.mdx
import { useDispatch, useSelector } from 'react-redux';
import { addTodo } from './todoAction.js';

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

const handleAdd = () => {
dispatch(addTodo('新项'));
};

return (
<div>
<button onClick={handleAdd}>增加代办</button>
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
</div>
);
}