Redux Toolkit 快速上手

FreeGuideOnline 14阅读 2026-07-13

bash npm create vite@latest redux-toolkit-demo -- --template react cd redux-toolkit-demo npm install


### 安装 Redux Toolkit 和 React-Redux

```bash
npm install @reduxjs/toolkit react-redux
  • @reduxjs/toolkit:包含核心工具函数。
  • react-redux:用于在 React 中连接 Redux Store。

核心概念与第一个 Slice

Redux Toolkit 的核心是 Slice。一个 Slice 将某个功能模块的 state、reducer 和 actions 封装在一起。

创建计数器 Slice

src 目录下新建 store 文件夹,然后创建 counterSlice.js

// src/store/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',            // slice 名称,作为 action type 前缀
  initialState: {
    value: 0,
  },
  reducers: {
    increment: (state) => {
      // 直接修改 state,Immer 会处理不可变更新
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload;
    },
  },
});

// 导出自动生成的 action creators
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
// 导出 reducer
export default counterSlice.reducer;

解析:

  • createSlice 需要 nameinitialStatereducers 字段。
  • reducers 中的每个函数可以接收 stateaction,我们直接操作 state,无需返回新对象。
  • action.payload 自动携带调用时传入的参数。
  • createSlice 自动生成对应名称的 action types,如 counter/increment

创建并配置 Store

Store 是整个应用的单一状态树。使用 configureStore 可以一行代码创建 store,并自动合并多个 reducer。

创建 src/store/index.js

// src/store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,   // 将 counter reducer 挂载到 state.counter
  },
});
  • configureStore 默认启用 Redux DevTools 扩展和 redux-thunk 中间件。
  • 如果有多个 Slice,只需在 reducer 对象中继续添加即可。

在 React 中连接 Store

使用 react-redux 提供的 <Provider> 包裹根组件,并将 store 传入。

修改 src/main.jsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { store } from './store';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

在组件中使用 State 和 Dispatch

react-redux 提供了两个核心 Hook:useSelector 用于读取状态,useDispatch 用于派发 action。

修改 src/App.jsx

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, incrementByAmount } from './store/counterSlice';

function App() {
  const count = useSelector((state) => state.counter.value);
  const dispatch = useDispatch();

  return (
    <div style={{ textAlign: 'center', marginTop: '2rem' }}>
      <h1>计数器{count}</h1>
      <button onClick={() => dispatch(increment())}>+</button>
      <button onClick={() => dispatch(decrement())}>-</button>
      <button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
    </div>
  );
}

export default App;

说明:

  • useSelector 接收一个函数,从整个 state 中挑选需要的数据,并自动订阅 store 的变化。
  • useDispatch 返回 store 的 dispatch 方法,用于触发 action creators 生成的 action。

处理异步逻辑:createAsyncThunk

真实的项目中,数据往往来自 API 调用。Redux Toolkit 提供了 createAsyncThunk 来优雅地处理异步请求,并自动生成 pending、fulfilled、rejected 三种 action。

示例:获取用户列表

假设我们有一个 JSONPlaceholder 接口。在 store 下新建 userSlice.js

// src/store/userSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

// 创建异步 thunk
export const fetchUsers = createAsyncThunk('users/fetchUsers', async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/users');
  return response.json(); // 自动成为 fulfilled action 的 payload
});

const userSlice = createSlice({
  name: 'users',
  initialState: {
    users: [],
    status: 'idle',     // 'idle' | 'loading' | 'succeeded' | 'failed'
    error: null,
  },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUsers.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(fetchUsers.fulfilled, (state, action) => {
        state.status = 'succeeded';
        state.users = action.payload;
      })
      .addCase(fetchUsers.rejected, (state, action) => {
        state.status = 'failed';
        state.error = action.error.message;
      });
  },
});

export default userSlice.reducer;

然后将 userReducer 添加到 store:

// store/index.js
import userReducer from './userSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
    users: userReducer,    // 新增
  },
});

在组件中使用:

import { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchUsers } from './store/userSlice';

function Users() {
  const dispatch = useDispatch();
  const { users, status, error } = useSelector((state) => state.users);

  useEffect(() => {
    if (status === 'idle') {
      dispatch(fetchUsers());
    }
  }, [status, dispatch]);

  if (status === 'loading') return <p>加载中...</p>;
  if (status === 'failed') return <p>错误: {error}</p>;

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

export default Users;

关键点:

  • createAsyncThunk 第一个参数是 action type 前缀,第二个是异步函数。
  • extraReducers 通过 builder 模式处理 thunk 的生命周期 action。
  • 通过 status 字段可以轻松实现加载状态和错误展示,无需额外 boolean。

使用 Immer 更新嵌套对象

Redux Toolkit 内置 Immer,允许我们以可变的方式更新深层嵌套的 state,但前提是不要混用可变与不可变操作。以下是一个嵌套更新的示例:

reducers: {
  updateAddress: (state, action) => {
    // 直接修改深层属性,Immer 会转换为不可变更新
    state.user.address.city = action.payload;
  },
}