大家好,我是小杨。今天我想用最通俗的方式,带你彻底理解Redux的工作流程。还记得我第一次接触Redux时,面对各种概念简直一头雾水。但现在回头看,它的设计其实非常精妙!
从一个生活场景说起
想象一下你去银行取钱的过程:
- 填写取款单(Action) - 说明你要做什么
- 柜台处理(Reducer) - 根据取款单更新账户余额
- 查看余额(Store) - 确认最新的账户状态
这就是Redux的核心思想!现在让我们深入技术细节。
Redux的三个核心角色
1. Store - 数据的"保险库"
javascript
// Store就像整个应用的数据中心
import { createStore } from 'redux';
// 创建Store时需要传入一个reducer
const store = createStore(counterReducer);
// 我们可以随时查看当前状态
console.log(store.getState()); // { count: 0 }
// 也可以订阅状态变化
const unsubscribe = store.subscribe(() => {
console.log('状态更新了:', store.getState());
});
2. Action - 变化的"指令书"
javascript
// Action就是一个普通的JavaScript对象
const incrementAction = {
type: 'INCREMENT', // 必须的type字段,描述要做什么
payload: 5 // 可选的数据载荷
};
// 通常我们会创建Action创建函数
const increment = (amount = 1) => ({
type: 'INCREMENT',
payload: amount
});
const decrement = (amount = 1) => ({
type: 'DECREMENT',
payload: amount
});
// 使用方式
store.dispatch(increment(5));
3. Reducer - 状态的"处理器"
javascript
// Reducer是一个纯函数,接收当前状态和action,返回新状态
const initialState = {
count: 0,
isLoading: false
};
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return {
...state,
count: state.count + action.payload
};
case 'DECREMENT':
return {
...state,
count: state.count - action.payload
};
case 'SET_LOADING':
return {
...state,
isLoading: action.payload
};
default:
return state;
}
};
完整工作流程:一场数据的"奇幻漂流"
让我们通过一个具体的例子,跟踪数据在Redux中的完整旅程:
javascript
// 步骤1:用户点击按钮,触发Action
function CounterComponent() {
const handleIncrement = () => {
// 创建并分发一个Action
store.dispatch({
type: 'INCREMENT',
payload: 1
});
};
return (
<div>
<button onClick={handleIncrement}>+1</button>
</div>
);
}
javascript
// 步骤2:Store接收到Action,调用Reducer
const currentState = { count: 0 };
const action = { type: 'INCREMENT', payload: 1 };
// Reducer处理,生成新状态
const newState = counterReducer(currentState, action);
console.log(newState); // { count: 1 }
javascript
// 步骤3:Store更新状态,通知所有订阅者
// 在createStore内部,大致是这样的逻辑:
class MyStore {
constructor(reducer) {
this.state = undefined;
this.listeners = [];
this.reducer = reducer;
}
dispatch(action) {
// 调用reducer生成新状态
this.state = this.reducer(this.state, action);
// 通知所有监听者
this.listeners.forEach(listener => listener());
}
subscribe(listener) {
this.listeners.push(listener);
}
getState() {
return this.state;
}
}
在React中的实际应用
光有Redux还不够,我们需要把它连接到React组件:
javascript
// 使用react-redux连接Store和组件
import { Provider, connect } from 'react-redux';
// 根组件包裹Provider
function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
// 连接组件和Store
const mapStateToProps = (state) => ({
count: state.count
});
const mapDispatchToProps = {
increment: () => ({ type: 'INCREMENT', payload: 1 }),
decrement: () => ({ type: 'DECREMENT', payload: 1 })
};
const Counter = connect(
mapStateToProps,
mapDispatchToProps
)(({ count, increment, decrement }) => (
<div>
<span>计数: {count}</span>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
));
异步操作:加入Middleware的"四重奏"
现实应用少不了异步操作,这时候就需要中间件登场:
javascript
// 使用redux-thunk处理异步
const fetchUserData = (userId) => {
// 返回一个函数,而不仅仅是对象
return async (dispatch, getState) => {
dispatch({ type: 'FETCH_USER_START' });
try {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
dispatch({
type: 'FETCH_USER_SUCCESS',
payload: userData
});
} catch (error) {
dispatch({
type: 'FETCH_USER_FAILURE',
payload: error.message
});
}
};
};
// 在组件中分发thunk action
store.dispatch(fetchUserData(123));
现代Redux Toolkit:简化流程
新的Redux Toolkit让这一切变得更简单:
javascript
import { createSlice, configureStore } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
incremented: (state, action) => {
state.value += action.payload;
},
decremented: (state, action) => {
state.value -= action.payload;
}
}
});
const store = configureStore({
reducer: counterSlice.reducer
});
// 自动生成action creators
console.log(counterSlice.actions.incremented(5));
// { type: 'counter/incremented', payload: 5 }
我总结的工作流程口诀
为了帮助记忆,我总结了这样一个口诀:
"组件分发Action,Store接收传Reducer
Reducer纯函数算,返回新State换
Store更新通知变,组件重渲染界面"
实际项目中的架构思考
经过多个项目的实践,我发现理解Redux工作流程的关键在于:
- 单向数据流 - 数据永远朝着一个方向流动
- 不可变性 - 状态不会被直接修改,总是创建新对象
- 纯函数 - Reducer没有副作用,同样的输入永远得到同样的输出
- 可预测性 - 整个状态变化过程都是透明可追踪的
调试技巧:让数据流可视化
Redux DevTools让整个工作流程变得肉眼可见:
javascript
javascript
// 安装浏览器扩展后,你可以:
// 1. 查看每个Action的详细内容
// 2. 跟踪状态如何随时间变化
// 3. "时间旅行"到任意时刻的状态
// 4. 重放Action序列
const store = createStore(
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
Redux的工作流程就像一场精心编排的交响乐,每个部分各司其职,共同奏出和谐的数据流动乐章。希望这个解释能帮你真正理解Redux的精髓!
⭐ 写在最后
请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.
✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式
✅ 认为我部分代码过于老旧,可以提供新的API或最新语法
✅ 对于文章中部分内容不理解
✅ 解答我文章中一些疑问
✅ 认为某些交互,功能需要优化,发现BUG
✅ 想要添加新功能,对于整体的设计,外观有更好的建议
✅ 一起探讨技术加qq交流群:906392632
最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!