前言:为什么你觉得 Redux 绕?
很多同学在学习 Redux 时,会被 Action、Reducer、Dispatch、Store 这一堆名词绕晕。其实,Redux 的本质就是一个**“全店共享的中央账本”**。
在没有 Redux 的时候,组件传值像“传声筒”,父传子、子传孙,层级一深,代码就成了乱麻。而 Redux 让数据脱离了组件树,独立存在。
今天,我们以**“古茗奶茶下单系统”**为例,用最现代的 Redux Toolkit (RTK) 方案,完成从零到一的进化。
第一步:建立心智模型——“古茗店长笔记”
在动手写代码前,先记住这个映射关系:
- Store(大账本) :古茗店里唯一的中央账本,记录了所有库存和订单。
- Slice(部门) :账本里的分区。比如“购物车部”、“用户部”。
- Action(申请单) :你想改账本?必须填申请单。比如“加一杯杨梅冰”。
- Reducer(财务主管) :唯一有权改账本的人。他看到申请单,亲自划掉旧数字,写上新数字。
- Selector(监控器) :收银台的屏幕。账本一变,屏幕自动刷新显示。
第二步:环境搭建(起步)
现在我们不再写老旧的 Redux 模板,直接上 Redux Toolkit。
codeBash
npm install @reduxjs/toolkit react-redux
第三步:编写业务逻辑切片 (Slice)
我们要处理购物车业务。新建 src/features/cartSlice.js:
codeJavaScript
import { createSlice } from '@reduxjs/toolkit';
const cartSlice = createSlice({
name: 'cart', // 部门名称
initialState: {
items: [], // 购物车奶茶列表
total: 0 // 总金额
},
reducers: {
// 申请单1:加入购物车
addToCart: (state, action) => {
// action.payload 就是传进来的奶茶:{ name: '杨梅冰', price: 15 }
state.items.push(action.payload);
state.total += action.payload.price;
},
// 申请单2:清空购物车
clearCart: (state) => {
state.items = [];
state.total = 0;
}
}
});
export const { addToCart, clearCart } = cartSlice.actions; // 导出申请单
export default cartSlice.reducer; // 导出财务主管
第四步:配置中央仓库 (Store)
新建 src/app/store.js,把各部门主管集合起来:
codeJavaScript
import { configureStore } from '@reduxjs/toolkit';
import cartReducer from '../features/cartSlice';
export const store = configureStore({
reducer: {
cart: cartReducer, // 注册购物车部门
// user: userReducer, 以后有用户部门再往这加
}
});
第五步:全局注入
在入口文件 main.jsx 中,用 把账本发给全店:
codeJsx
import { Provider } from 'react-redux';
import { store } from './app/store';
ReactDOM.createRoot(document.getElementById('root')).render(
<Provider store={store}>
<App />
</Provider>
);
第六步:在组件中使用(实战演练)
1. 提交申请单(Dispatching Actions)
在 Menu.jsx(菜单页),点击按钮加奶茶:
codeJsx
import { useDispatch } from 'react-redux';
import { addToCart } from './features/cartSlice';
function Menu() {
const dispatch = useDispatch(); // 拿到那个“发单机”
return (
<button onClick={() => dispatch(addToCart({ name: '杨梅冰', price: 15 }))}>
点一杯杨梅冰
</button>
);
}
2. 查看屏幕显示(Selecting State)
在 Header.jsx(页眉),实时显示金额:
codeJsx
import { useSelector } from 'react-redux';
function Header() {
// 盯着账本里的 cart 部分看
const { total, items } = useSelector((state) => state.cart);
return (
<div>
<span>购物车数量:{items.length}</span>
<span>总金额:¥{total}</span>
</div>
);
}
第七步:进阶——处理异步业务 (Async Thunk)
现实中,我们要领优惠券,需要等接口返回。
codeJavaScript
// 在 cartSlice.js 中添加
import { createAsyncThunk } from '@reduxjs/toolkit';
export const fetchCoupon = createAsyncThunk('cart/fetchCoupon', async () => {
const res = await fetch('/api/get-coupon');
return res.json(); // 返回 { discount: 5 }
});
// 在 createSlice 的 extraReducers 中监听
extraReducers: (builder) => {
builder.addCase(fetchCoupon.fulfilled, (state, action) => {
state.total -= action.payload.discount; // 领券成功,减钱!
});
}
总结:精通 Redux 的三字经
- 分 (Slice) :按业务拆分模块,别把所有东西塞一起。
- 选 (Selector) :组件只拿自己需要的那一小块数据,避免无效渲染。
- 单 (Dispatch) :改数据必须发 Action,不要在组件里直接改 State。
什么时候用 Redux?
- 跨页面共享:用户信息、购物车、全局主题。
- 频繁变动:多处组件依赖同一个数据源。
- 本地缓存:比如电视机播放白屏优化中的“离线资源列表”。