Redux 工作原理
一句话概括:Redux 是一个集中式状态管理库,通过单向数据流管理应用状态,让状态变化变得可预测。
理解 Redux,只需要先掌握 Store、Action、Reducer、Dispatch 四个核心概念。
一、Redux 解决什么问题?
假设 React 应用中有多个组件需要共享用户信息:
css
App
/ \
Header Main
| |
Avatar Profile
如果使用 React 自身的状态管理,可能需要通过 Props 层层传递,或者使用 Context。
Redux 提供了另一种方案:
把多个组件需要共享的状态统一放到 Store 中管理。
css
Redux Store
userInfo
count
theme
│
┌────┴────┐
▼ ▼
Header Profile
组件可以直接读取 Store 中的数据,并通过规定的方式更新状态。
注意:Redux 不是为了解决所有 Props 传递问题而设计的,它更适合管理具有一定复杂度的共享状态。
二、Redux 的四个核心概念
1. Store:状态仓库
Store 是保存应用状态的地方。
css
{
count: 0,
user: {
name: "Tom"
}
}
整个 Redux 应用通常只有一个 Store。
2. Action:描述发生了什么
Action 是一个普通 JavaScript 对象,必须包含 type 属性。
bash
{
type: "counter/increment"
}
它只描述发生了什么,并不直接修改状态。
也可以携带数据:
bash
{
type: "counter/add",
payload: 5
}
3. Reducer:决定如何更新状态
Reducer 是一个函数:
perl
(state, action) => newState
例如:
javascript
function counterReducer(state = { count: 0 }, action) {
switch (action.type) {
case "counter/increment":
return {
...state,
count: state.count + 1
};
default:
return state;
}
}
Reducer 根据旧状态和 Action 计算新状态。
Reducer 必须是纯函数,不能直接修改原有状态,也不应该包含异步操作等副作用。
4. Dispatch:发起状态更新
组件通过 dispatch 发送 Action。
bash
store.dispatch({
type: "counter/increment"
});
Redux 接收到 Action 后,就会调用 Reducer 计算新状态。
三、Redux 的完整工作流程
这是面试最重要的部分。
scss
React Component
│
│ 用户点击按钮
▼
dispatch(action)
│
▼
Redux Store
│
│ 调用
▼
reducer(state, action)
│
│ 返回新状态
▼
Redux Store
│
│ 保存新状态
▼
通知订阅者
│
▼
React-Redux 检查状态变化
│
▼
需要更新的组件重新渲染
核心:组件不能直接修改 Redux 状态,只能通过 dispatch → reducer → 新状态的方式更新。
这种机制叫做单向数据流(One-Way Data Flow) 。
四、用代码理解 Redux
先不引入 React,只看 Redux 本身。
javascript
import { createStore } from "redux";
// 1. 定义 Reducer
function reducer(state = { count: 0 }, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
default:
return state;
}
}
// 2. 创建 Store
const store = createStore(reducer);
// 3. 订阅状态变化
store.subscribe(() => {
console.log("状态更新:", store.getState());
});
// 4. 获取状态
console.log(store.getState()); // { count: 0 }
// 5. 发送 Action
store.dispatch({ type: "increment" });
// 输出:状态更新:{ count: 1 }
注意:这里使用旧版 createStore 是为了方便理解原理。现代 Redux 官方推荐使用 Redux Toolkit 的 configureStore。
dispatch 内部发生了什么?
可以用一段简化代码理解 Redux:
scss
function createStore(reducer) {
let state;
const listeners = [];
function getState() {
return state;
}
function dispatch(action) {
// 1. 调用 Reducer,计算新状态
state = reducer(state, action);
// 2. 通知订阅者
listeners.forEach(listener => listener());
}
function subscribe(listener) {
listeners.push(listener);
}
// 初始化状态
dispatch({ type: "@@INIT" });
return {
getState,
dispatch,
subscribe
};
}
这是教学简化版,省略了订阅取消、异常检查等实现细节。
你会发现 Redux 的核心其实很简单:
- 使用闭包保存
state。 - 通过
dispatch调用 Reducer 更新状态。 - 使用发布订阅模式通知状态变化。
五、Redux 和 React 如何配合?
Redux 本身与 React 无关。
React 项目通常通过 react-redux 连接 Redux。
主要使用两个 Hook:
useSelector:读取 Store 状态。
ini
const count = useSelector(state => state.counter.count);
useDispatch:获取 dispatch 方法。
ini
const dispatch = useDispatch();
dispatch({ type: "counter/increment" });
完整示例:
javascript
function Counter() {
const count = useSelector(state => state.counter.count);
const dispatch = useDispatch();
return (
<div>
<p>{count}</p>
<button
onClick={() => dispatch({ type: "counter/increment" })}
>
+1
</button>
</div>
);
}
当 Store 状态更新时:
- React-Redux 收到 Store 的更新通知。
useSelector重新计算选中的值。- 如果选中的结果发生变化,触发对应组件重新渲染。
注意:不是 Store 中任意状态发生变化,所有使用 Redux 的组件都会重新渲染。
六、Redux 如何处理异步操作?
Reducer 必须是纯函数,不能在里面直接发请求。
Redux 通过 Middleware(中间件) 处理异步逻辑。
例如使用 Redux Thunk:
ini
const fetchUser = () => async (dispatch) => {
const res = await fetch("/api/user");
const user = await res.json();
dispatch({
type: "user/setUser",
payload: user
});
};
执行流程:
scss
组件 dispatch(fetchUser())
│
▼
Thunk Middleware
│
▼
发起 API 请求
│
▼
获取响应数据
│
▼
dispatch 普通 Action
│
▼
Reducer
│
▼
Store 更新
│
▼
React 重新渲染
Middleware 的本质:拦截或增强 dispatch,使 Redux 能够处理异步操作、日志等逻辑。
七、Redux Toolkit 是什么?
现在开发 React 项目,通常使用 Redux Toolkit(RTK) ,而不是手动编写大量原生 Redux 代码。
RTK 是 Redux 官方推荐的工具集,主要简化:
| 传统 Redux | Redux Toolkit |
|---|---|
| 手写 Action Type | 自动生成 |
| 手写 Action Creator | 自动生成 |
| 手写 Reducer | createSlice |
| 手动保证不可变更新 | 使用 Immer 简化 |
| 手动配置 Store | configureStore |
| 手动配置异步逻辑 | createAsyncThunk 等 |
例如:
javascript
import { createSlice } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: "counter",
initialState: {
count: 0
},
reducers: {
increment(state) {
state.count++;
}
}
});
export const { increment } = counterSlice.actions;
export default counterSlice.reducer;
这里的:
ini
state.count++;
看起来违反了 Reducer 不能修改状态的原则。
实际上,Redux Toolkit 内部通过 Immer 将这种写法转换为不可变状态更新,因此不会直接修改原始状态。
八、面试如何回答 Redux 的工作原理?
可以直接用下面这段回答:
Redux 是一个基于单向数据流的状态管理库,主要包含 Store、Action、Reducer 三个核心概念。
Store 负责保存应用状态,组件通过 dispatch 发送 Action,Reducer 根据当前状态和 Action 计算并返回新状态,Store 保存新状态后通知订阅者。
在 React 中,React-Redux 通过订阅 Store 的变化,让使用 useSelector 的组件在选中数据发生变化时重新渲染。
Redux 内部主要依赖闭包保存状态、发布订阅模式通知更新,以及 Reducer 实现可预测的状态变更。对于异步操作,可以通过 Redux Thunk 等中间件处理。
现代项目一般使用 Redux Toolkit 来简化开发。
最后总结
掌握 Redux,最重要的其实只有两层:
第一层:工作流程
dispatch → action → reducer → store → React 更新
第二层:底层原理
- 闭包:保存状态。
- 发布订阅模式:通知状态变化。
- 纯函数:保证状态更新可预测。
- 中间件:扩展 dispatch 的能力。
你之前学过 Zustand,可以把两者联系起来理解:
Redux 和 Zustand 都是状态管理工具,但 Redux 更强调通过 Action 和 Reducer 规范状态变更,而 Zustand 通常允许通过 Store 中定义的 Action 函数直接调用 set 更新状态。
对于面试,理解 Redux 的核心工作流程和发布订阅机制,比死记大量 API 更有价值。