Flandre923
2155 words
11 minutes
Redux redux tookit

什么是 redux 和 redux tookit#

  • Redux:是一个独立的状态管理库,它不依赖于特定的前端框架(如 React),但常与 React 配合使用。其核心作用是集中管理应用中所有组件的状态,使状态变化可预测、可追踪。
  • Redux Toolkit:是 Redux 官方推荐的工具库,它封装了 Redux 开发中的常见任务,简化了 Redux 的配置和使用。例如: 1.快速创建 store 2.简化 reducer 的编写 3.自动生成 action 和 action creator 4.内置处理异步操作的中间件

相关基础概念#

1. 状态(State)#

状态是一个存储应用数据的对象,它包含了应用运行过程中需要用到的各种信息。例如:

// 一个简单的状态示例
const state = {
  user: { name: "张三", age: 25 },
  theme: "light",
  count: 0
};

这些数据会随着用户操作(如点击按钮、输入文本等)发生变化,状态的变化直接反映了应用的行为。

2. 状态管理#

状态管理是一种设计模式,用于规范状态的创建、读取、更新和删除过程。它主要解决以下问题:

  • 多个组件共享同一状态时,确保状态变化在所有组件中同步
  • 避免组件嵌套过深时,通过 props 层层传递状态的繁琐操作
  • 追踪状态的变化历史,便于调试和问题定位

3.Redux 设计理念#

  1. 单一数据源:整个应用的状态被存储在一个统一的 store 中,便于集中管理和监控。
  2. 纯函数(Reducer):reducer 是修改状态的唯一入口,它接收当前状态和 action,返回新的状态,且过程中不会产生副作用(如修改参数、调用异步接口等)。
  3. Immutable(不可变性):Redux 规定状态一旦创建就不能被直接修改,每次状态更新都需要返回一个全新的状态对象。这一特性保证了状态变化的可追踪性。

注意:Redux Toolkit 通过内置的 Immer 库,允许我们在 reducer 中 “直接修改” 状态(如 state.value += 1),但这只是语法糖,底层仍会生成新的状态对象,不违反 immutable 原则。

  1. 通过 dispatch action 改变状态:store 中的状态只能通过 dispatch 一个 action 来修改,action 描述了 “要做什么”,reducer 根据 action 决定如何修改状态。 5.支持异步操作:通过 redux-thunk 中间件(Redux Toolkit 已默认集成),可以 dispatch 函数来处理异步操作(如接口请求)。

4. Redux 核心概念#

  1. store:存储整个应用状态的容器,包含 getState()(获取状态)、dispatch(action)(触发状态更新)等方法。
  2. action:描述状态变化的普通对象,必须包含 type 属性(表示动作类型),可选包含 payload(传递的数据)。例如:{ type: ‘counter/increment’, payload: 1 }。
  3. reducer:根据 action 处理状态的纯函数,格式为 (state, action) => newState。
  4. dispatch:store 提供的方法,用于将 action 发送给 reducer,从而触发状态更新。

三、实战:使用 Redux Toolkit 实现计数器#

下面通过一个计数器案例,演示 Redux Toolkit 的具体用法,包括环境搭建、store 配置、状态定义、组件使用等步骤。

1. 环境搭建#

步骤 1:安装 create-react-app(用于创建 React 项目)

npm install react-create-app -g

步骤 2:创建 TypeScript 项目并进入目录

create-react-app redux-demo --template typescript
cd redux-demo

步骤 3:安装 Redux 与 Redux Toolkit

npm install redux redux-toolkit

步骤 4:启动项目

npm install 
npm start

2. 创建 store#

store 是存储状态的容器,通过 Redux Toolkit 的 configureStore 函数创建,代码如下:

// ./state/store.ts
import { configureStore } from "@reduxjs/toolkit";

export const store = configureStore({
  reducer: {
    // 后续会添加 reducer
  },
}); 

export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch

configureStore:Redux Toolkit 提供的创建 store 的函数,内部已默认配置好常用中间件(如 redux-thunk)。 reducer:配置 store 对应的 reducer(状态更新函数),后续会将计数器的 reducer 添加到这里。 RootState:通过 ReturnType 提取 store 状态的类型,用于在组件中类型安全地获取状态。 AppDispatch:提取 dispatch 函数的类型,确保在组件中 dispatch 动作时类型正确。

3. 在应用中注入 store#

通过 React-Redux 提供的 Provider 组件,将 store 注入整个应用,使所有组件都能访问 store:

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


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

<Provider store={store}>:将 store 作为参数传递给 Provider 组件,Provider 会通过 React 的上下文(Context)机制,让所有子组件都能访问 store。

4. 创建计数器切片(Slice)#

Redux Toolkit 中的 “切片(Slice)” 是一个包含 reducer 和 action 的对象,通过 createSlice 函数创建。计数器切片的代码如下:

//./state/counter/counterSlice.ts
import {createAsyncThunk, createSlice, PayloadAction} from "@reduxjs/toolkit";

interface CounterState {
    value:number;
}

const initialState:CounterState = {
    value:0,
}

const counterSlice = createSlice({
    name:"counter",
    initialState,
    reducers:{
        increment: (state) => {
            state.value += 1;
        },
        decrement: (state) => {
            state.value -= 1;
        },
        incrementByAmount: (state, action :PayloadAction<{value:number}>)=>{
            state.value += action.payload.value;
        } 
    },
    extraReducers: (builder) => {
        builder
        .addCase(incrementAsync.pending,()=>{
            console.log("incrementAsync.pending");
        })
        .addCase(incrementAsync.fulfilled, (state, action:PayloadAction<{value:number}>)=>{
            state.value += action.payload.value; 
        })
    },
});

export const incrementAsync = createAsyncThunk(
    "counter/incrementAsync",
    async (amount:number) => {
        await new Promise((resolve) => setTimeout(resolve, 1000));
        return {value:amount};
    }
);

export const {increment, decrement ,incrementByAmount}  = counterSlice.actions;

export default counterSlice.reducer;

关键代码解析:

  1. 定义状态类型与初始状态
interface CounterState {
    value:number;
}
const initialState: CounterState = { value: 0 };

CounterState 接口定义了计数器状态的结构(仅有一个 value 属性,类型为数字)。 initialState 是计数器的初始状态,初始值为 0。

创建切片(createSlice)

  • name: “counter”:切片名称,会作为 action 类型的前缀(如 counter/increment)。
  • initialState:传入初始状态。
  • reducers:定义同步 action 对应的处理函数(reducer):
    • increment:每次调用时,将 state.value 加 1。
    • decrement:每次调用时,将 state.value 减 1。
    • incrementByAmount:接收一个包含 value 的 payload,将 state.value 加上该值。
  • extraReducers:处理异步 action(如 incrementAsync)的状态变化,通过 builder 模式监听异步操作的不同阶段(pending、fulfilled 等)。
  1. 创建异步 action(createAsyncThunk)

export const incrementAsync = createAsyncThunk(
    "counter/incrementAsync",
    async (amount: number) => {
        await new Promise((resolve) => setTimeout(resolve, 1000)); // 模拟接口请求延迟
        return { value: amount };
    }
);
  • 用于创建处理异步操作的 action,第一个参数是 action 类型前缀,第二个参数是异步函数。
  • 异步函数中通过 setTimeout 模拟接口请求(延迟 1 秒),成功后返回要传递的数据({ value: amount })。
  • 异步操作有三个状态:pending(进行中)、fulfilled(成功)、rejected(失败),在 extraReducers 中分别处理。
 reducers:{
        increment: (state) => {
            state.value += 1;
        },
        decrement: (state) => {
            state.value -= 1;
        },
        incrementByAmount: (state, action :PayloadAction<{value:number}>)=>{
            state.value += action.payload.value;
        } 
    },
    extraReducers: (builder) => {
        builder
        .addCase(incrementAsync.pending,()=>{
            console.log("incrementAsync.pending");
        })
        .addCase(incrementAsync.fulfilled, (state, action:PayloadAction<{value:number}>)=>{
            state.value += action.payload.value; 
        })
    },
  1. 导出 action 与 reducer
  • export const { increment, decrement, incrementByAmount } = counterSlice.actions:导出同步 action,用于在组件中触发状态更新。
  • export default counterSlice.reducer:导出切片的 reducer,需添加到 store 中。
  1. 将切片 reducer 添加到 store 修改 store.ts,将计数器切片的 reducer 配置到 store 中:
// ./state/store.ts
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./counter/counterSlice"; // 导入计数器 reducer

export const store = configureStore({
  reducer: {
    counter: counterReducer, // 将计数器 reducer 添加到 store
  },
}); 

export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch

此时 store 的状态结构为 { counter: { value: number } },counter 是切片对应的键名。

  1. 在组件中使用计数器状态 创建一个 Counter 组件,通过 useSelector 获取状态,通过 useDispatch 触发 action:
import { useDispatch, useSelector } from "react-redux";
import { AppDispatch, RootState } from "../state/store";
import { decrement, increment, incrementByAmount, incrementAsync } from "../state/counter/counterSlice";

const Counter = () => {
    // 从 store 中获取计数器的值
    const count = useSelector((state: RootState) => state.counter.value);
    // 获取 dispatch 函数
    const dispatch = useDispatch<AppDispatch>();
    
    return (
        <div>
            <h2>{count}</h2>
            <div>
                {/* 触发同步 action */}
                <button onClick={() => dispatch(increment())}>+1</button>
                <button onClick={() => dispatch(decrement())}>-1</button>
                <button onClick={() => dispatch(incrementByAmount({ value: 10 }))}>+10</button>
                {/* 触发异步 action(延迟 1 秒后 +10) */}
                <button onClick={() => dispatch(incrementAsync(10))}>Async +10</button>
            </div>
        </div>
    )
}

export default Counter;
  • useSelector:从 store 中提取需要的状态,参数是一个函数,接收整个状态对象,返回需要的部分(这里返回 state.counter.value)。
  • useDispatch:获取 dispatch 函数,用于触发 action。通过 AppDispatch 类型约束,确保 dispatch 的 action 类型正确。
  • 点击按钮时,通过 dispatch 调用对应的 action(同步或异步),从而更新计数器状态。

四、Redux 调试工具#

Redux 提供了强大的调试工具 redux-devtools-extension,可以帮助我们追踪状态的变化历史,便于调试。

使用方法:

  • 浏览器安装插件:在 Chrome 应用商店搜索 “Redux DevTools” 并安装。
  • Redux Toolkit 的 configureStore 已默认集成调试工具,无需额外配置。
  • 启动项目后,打开浏览器开发者工具(F12),切换到 “Redux” 标签页,即可查看:
    • 每次 a`ction 的类型、 payload 及触发时间
    • 状态的前后变化对比
    • `可以重放、取消 action,观察状态变化
Redux redux tookit
https://fuwari.vercel.app/posts/front/react/redux_redux_tookit/
Author
Flandre923
Published at
2025-08-16