创见博客
Redux Tookit的基本使用
七崽爱吃小饼干2026/01/13阅读 0专栏 React

Redux Toolkit 基础使用

Redux Toolkit(简称 RTK),它是Redux官方推出的官方推荐写法,解决了原生Redux样板代码过多、配置繁琐、需要手动集成中间件等痛点,新项目必须用RTK,而非原生Redux

一、核心认知:Redux Toolkit 是什么 & 解决什么问题

Redux 是 React 的全局状态管理库,用来管理组件之间共享的、跨层级的公共数据(比如用户信息、主题配置、购物车数据等)。 原生 Redux 开发有3大痛点:

  1. 需要手动写 action、actionCreator、reducer,样板代码巨多;
  2. 必须手动安装 redux-thunk 才能处理异步请求;
  3. 状态修改必须写纯函数、深拷贝,容易出错;
  4. 还要手动组合 reducer、配置 store,步骤繁琐。

Redux Toolkit 就是 Redux 的官方封装工具集,把原生Redux的所有繁琐配置都内置封装,提供了极简的API,核心做到:少写代码、少配依赖、少踩坑,是现在React生态中Redux的唯一推荐方案。


二、核心依赖安装(必装2个)

Redux Toolkit 核心依赖只有2个,无需额外装redux、redux-thunk、immer(这些都内置了),一行命令安装即可:

bash
# npm 安装
npm install @reduxjs/toolkit react-redux

# yarn 安装
yarn add @reduxjs/toolkit react-redux
  • @reduxjs/toolkit:RTK核心库,封装了创建store、reducer、异步action的所有API;
  • react-redux:连接 Redux 和 React 组件的桥梁,提供Provider、useSelector、useDispatch等核心hooks。

三、核心概念

原生Redux的概念很多(action、actionType、actionCreator、reducer、middleware、combineReducers等),RTK对其做了极大精简和封装,核心概念只剩3个,全部记住:

1. configureStore() - 创建全局唯一的 Store

configureStore 是 RTK 提供的创建store的核心方法,替代了原生Redux的createStore+combineReducers+applyMiddleware。

  • 作用:创建全局唯一的状态仓库,所有组件的公共状态都存在这里;
  • 特点:内置redux-thunk(直接处理异步请求)、内置状态校验、自动合并多个reducer,无需任何额外配置。

2. createSlice() - RTK的「核心核心」,重中之重

createSlice 是 RTK 最核心的API,90%的业务代码都靠它实现,直译是「创建切片」。

  • 作用:一个方法封装了 原生Redux的 action + reducer 所有功能,无需手动定义actionType、actionCreator;
  • 核心原理:基于 immer 库实现,允许在reducer中「直接修改状态」(无需深拷贝、无需返回新状态),底层会自动转换成不可变数据,既简洁又不会出错;
  • 切片的含义:把全局状态按业务模块拆分(比如用户模块、购物车模块、商品模块),每个模块就是一个slice,最终把所有slice合并到store中,便于维护。

3. createAsyncThunk() - 处理异步请求

React 项目中,99%的场景都需要请求接口获取数据,这个API就是RTK专门用来处理异步action的(比如请求接口获取用户信息、商品列表)。

  • 作用:封装异步逻辑(axios请求),自动分发「请求中/请求成功/请求失败」三种状态,让异步数据请求与状态管理完美结合;
  • 特点:无需手动写dispatch,无需手动管理loading/error状态,与createSlice无缝联动。

四、完整基础使用流程

整体目录规范(React项目通用,必须遵守,方便维护)

所有Redux相关代码统一放在 src/store 目录下,按模块拆分,基础结构如下:

src
└── store/
    ├── modules/        # 所有业务模块的slice(核心)
    │   ├── userSlice.js # 用户模块:登录、个人信息等
    │   └── cartSlice.js # 购物车模块:添加、删除商品等
    └── index.js        # 创建全局store,合并所有slice

步骤1:创建全局 Store 仓库(src/store/index.js)

核心是调用 configureStore 方法,合并所有业务模块的reducer,整个项目只有1个store。

javascript
// 1. 导入RTK的核心方法
import { configureStore } from '@reduxjs/toolkit'
// 2. 导入各个业务模块的slice
import userReducer from './modules/userSlice'
import cartReducer from './modules/cartSlice'

// 3. 创建全局store并导出
const store = configureStore({
  // 合并所有slice的reducer,key自定义,value是slice的reducer
  reducer: {
    user: userReducer,
    cart: cartReducer
  }
})

// 导出store,供根组件使用
export default store

步骤2:将 Store 注入整个React应用(入口文件 src/main.jsx / src/index.js)

通过 react-redux 提供的 Provider 根组件,将创建好的store注入到整个React应用中,这样所有子组件都能访问到Redux的全局状态。

javascript
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
// 1. 导入Provider组件
import { Provider } from 'react-redux'
// 2. 导入全局store
import store from './store'

ReactDOM.createRoot(document.getElementById('root')).render(
  // 3. 用Provider包裹根组件,传入store属性
  <Provider store={store}>
    <App />
  </Provider>
)

步骤3:创建业务模块的 Slice(核心!以用户模块为例 src/store/modules/userSlice.js)

这是最核心的步骤,分为「同步修改状态」和「异步请求数据」两个最常用场景,全部实现。

场景1:纯同步操作(比如修改用户名称、切换登录状态)

javascript
// 1. 导入RTK核心方法
import { createSlice } from '@reduxjs/toolkit'

// 2. 定义初始状态:该模块的所有状态都在这里初始化
const initialState = {
  name: '张三',
  age: 20,
  isLogin: false, // 是否登录
  token: ''       // 登录令牌
}

// 3. 创建slice,核心配置3个参数
const userSlice = createSlice({
  // ① name:模块名称,必须唯一,用于区分不同slice
  name: 'user',
  // ② initialState:初始状态
  initialState,
  // ③ reducers:同步修改状态的方法集合(核心)
  // 这里的每一个函数,都是一个「同步action」,函数名就是action名称
  reducers: {
    // 修改用户名:直接修改状态,无需深拷贝!
    changeName(state, action) {
      state.name = action.payload // payload是传参,固定写法
    },
    // 用户登录:存入token,修改登录状态
    login(state, action) {
      state.token = action.payload.token
      state.isLogin = true
    },
    // 用户退出:重置状态
    logout(state) {
      state.token = ''
      state.isLogin = false
      state.name = '游客'
    }
  }
})

// 4. 必须导出:同步action方法(供组件调用,触发状态修改)
export const { changeName, login, logout } = userSlice.actions

// 5. 必须导出:当前slice的reducer(供store合并)
export default userSlice.reducer

场景2:异步操作(比如请求接口登录、获取用户信息,必用 createAsyncThunk)

在上面的同步代码基础上,新增异步逻辑,无缝联动,完整代码如下(真实项目直接改接口地址即可):

javascript
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import axios from 'axios' // 项目中请先安装:npm install axios

const initialState = {
  name: '张三',
  age: 20,
  isLogin: false,
  token: '',
  // 新增:异步请求的状态,用于页面loading/错误提示
  loading: false,
  error: ''
}

// ✅ 核心:创建异步action,处理接口请求
// createAsyncThunk(标识名, 异步回调函数)
// 回调函数的参数:组件调用时传入的参数;返回值:接口请求的结果
export const fetchLogin = createAsyncThunk(
  'user/fetchLogin', // 标识名:格式「模块名/方法名」,必须唯一
  async (loginForm, { rejectWithValue }) => {
    try {
      // 真实接口请求:用户名+密码登录
      const res = await axios.post('/api/login', loginForm)
      return res.data // 返回成功数据,会传给下方的extraReducers
    } catch (err) {
      // 请求失败:返回错误信息
      return rejectWithValue(err.response.data)
    }
  }
)

const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    changeName(state, action) { state.name = action.payload },
    logout(state) { state.token = ''; state.isLogin = false }
  },
  // ✅ 核心:处理异步action的「三种状态」,必须写在extraReducers里
  // pending: 请求中  fulfilled: 请求成功  rejected: 请求失败
  extraReducers: (builder) => {
    builder
      // 登录请求中
      .addCase(fetchLogin.pending, (state) => {
        state.loading = true
        state.error = ''
      })
      // 登录请求成功
      .addCase(fetchLogin.fulfilled, (state, action) => {
        state.loading = false
        state.token = action.payload.token // 接口返回的token
        state.isLogin = true
        state.name = action.payload.username // 接口返回的用户名
      })
      // 登录请求失败
      .addCase(fetchLogin.rejected, (state, action) => {
        state.loading = false
        state.error = action.payload.msg // 接口返回的错误信息
      })
  }
})

export const { changeName, logout } = userSlice.actions
export default userSlice.reducer

步骤4:组件中使用Redux(核心2个hooks,无其他)

在任意React组件中,想要读取Redux状态、修改Redux状态,只需要用 react-redux 提供的 2个专属hooks,无任何其他API,无需高阶组件、无需connect,这是React18的推荐写法:

1. useSelector - 读取/订阅 Redux 全局状态

  • 作用:从Redux的store中获取需要的状态数据,组件会自动订阅状态变化,状态更新时组件会重新渲染;
  • 语法:const 状态名 = useSelector( state => state.模块名.具体状态 )
  • 说明:state 就是store中合并的所有状态,模块名 是store/index.js中定义的key(比如user、cart)。

2. useDispatch - 触发action,修改 Redux 状态

  • 作用:获取Redux的dispatch方法,通过dispatch调用action方法,从而触发reducer执行,最终修改状态;
  • 语法:const dispatch = useDispatch() → dispatch( action方法(传参) )
  • 说明:无论是同步action(slice的reducers里的方法)还是异步action(createAsyncThunk创建的方法),调用方式完全一致!

组件完整使用示例(同步+异步)

javascript
import { useSelector, useDispatch } from 'react-redux'
// 导入需要的同步/异步action
import { changeName, logout, fetchLogin } from './store/modules/userSlice'

function UserInfo() {
  // 1. 读取Redux状态:解构赋值,按需获取
  const { name, age, isLogin, loading, error } = useSelector(state => state.user)
  
  // 2. 获取dispatch方法
  const dispatch = useDispatch()

  // 同步修改状态:调用同步action
  const handleChangeName = () => {
    dispatch(changeName('李四')) // payload就是传入的参数
  }

  // 异步请求:调用异步action(登录请求)
  const handleLogin = async () => {
    const loginForm = { username: 'admin', password: '123456' }
    dispatch(fetchLogin(loginForm)) // 传参就是接口需要的参数
  }

  // 同步退出登录
  const handleLogout = () => {
    dispatch(logout())
  }

  return (
    <div>
      <h2>用户名:{name}</h2>
      <h2>年龄:{age}</h2>
      <h2>是否登录:{isLogin ? '已登录' : '未登录'}</h2>
      {error && <p style={{color: 'red'}}>{error}</p>}
      
      <button onClick={handleChangeName}>修改用户名</button>
      <button onClick={handleLogin} disabled={loading}>{loading ? '登录中...' : '登录'}</button>
      <button onClick={handleLogout} disabled={!isLogin}>退出登录</button>
    </div>
  )
}

export default UserInfo

五、核心补充知识点

1. 为什么 RTK 允许直接修改 state?

原生Redux中,必须遵守不可变数据原则:不能直接修改state,必须返回一个新的state(否则无法触发组件更新),比如 return { ...state, name: '李四' }。

而RTK中,createSlice 内置了 immer 库,它会在底层做一个「代理」:你写的 state.name = '李四' 看起来是直接修改,但immer会自动将这个「可变操作」转换成「不可变操作」,生成一个新的状态对象,既保证了Redux的核心原则,又简化了代码。

结论:在RTK的reducers/extraReducers中,放心直接修改state!

2. action.payload 是什么?(固定写法)

payload 是 RTK 中传递参数的固定属性名,没有其他名字。

  • 当你调用 dispatch(changeName('李四')) 时,'李四' 就是payload;
  • 在reducer中,通过 action.payload 获取这个参数;
  • 如果需要传多个参数,直接传一个对象即可:dispatch(changeName({name: '李四', age: 25})),然后在reducer中解构 const {name, age} = action.payload。

3. 多模块状态如何拆分?

完全按照业务模块拆分即可,比如:

  • 用户相关:userSlice.js(登录、个人信息、退出)
  • 购物车相关:cartSlice.js(添加商品、删除商品、修改数量)
  • 商品相关:goodsSlice.js(商品列表、商品详情) 每个slice独立维护自己的状态和方法,最后在store中合并,高内聚低耦合,大型项目也能轻松维护。

六、总结

  1. Redux Toolkit (RTK) 是 Redux 官方推荐的唯一写法,解决原生Redux样板代码多的问题;
  2. 核心依赖:@reduxjs/toolkit + react-redux,无需其他依赖;
  3. 核心API:configureStore(创建store)、createSlice(核心,同步状态)、createAsyncThunk(异步请求);
  4. 组件核心hooks:useSelector(读状态)、useDispatch(改状态);
  5. 核心特性:内置redux-thunk、内置immer,允许直接修改state,异步同步调用方式一致;
  6. 目录规范:所有Redux代码放src/store,按模块拆分slice,便于维护。
评论
0/100