从 0 到 1 精通 Redux:从“绕晕”到“真香”的保姆级实战

33 阅读3分钟

前言:为什么你觉得 Redux 绕?

很多同学在学习 Redux 时,会被 Action、Reducer、Dispatch、Store 这一堆名词绕晕。其实,Redux 的本质就是一个**“全店共享的中央账本”**。

在没有 Redux 的时候,组件传值像“传声筒”,父传子、子传孙,层级一深,代码就成了乱麻。而 Redux 让数据脱离了组件树,独立存在。

今天,我们以**“古茗奶茶下单系统”**为例,用最现代的 Redux Toolkit (RTK)  方案,完成从零到一的进化。


第一步:建立心智模型——“古茗店长笔记”

在动手写代码前,先记住这个映射关系:

  1. Store(大账本) :古茗店里唯一的中央账本,记录了所有库存和订单。
  2. Slice(部门) :账本里的分区。比如“购物车部”、“用户部”。
  3. Action(申请单) :你想改账本?必须填申请单。比如“加一杯杨梅冰”。
  4. Reducer(财务主管) :唯一有权改账本的人。他看到申请单,亲自划掉旧数字,写上新数字。
  5. 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 的三字经

  1. 分 (Slice) :按业务拆分模块,别把所有东西塞一起。
  2. 选 (Selector) :组件只拿自己需要的那一小块数据,避免无效渲染。
  3. 单 (Dispatch) :改数据必须发 Action,不要在组件里直接改 State。

什么时候用 Redux?

  • 跨页面共享:用户信息、购物车、全局主题。
  • 频繁变动:多处组件依赖同一个数据源。
  • 本地缓存:比如电视机播放白屏优化中的“离线资源列表”。