RTK使用基本流程

依赖安装准备

RTK作为简化redux使用的工具包,在React中使用时二者都必不可少

cmd 复制代码
npm install react-redux @reduxjs/toolkit -s

使用

在开始进入具体的业务环境之前,我们先要对RTK整体使用步骤有一个大概的认识。由于RTK作为简化工具,所以使用RTK的过程中避免了原本使用redux时产生的大量样板代码,这里对其状态管理原理不做深入,旨在快速学习上手

  1. 创建Slice(createSlice):定义状态和对应的修改逻辑
  2. 配置Store(configureStore):组合所有的状态模块
  3. 连接React(Provider):Provider包裹顶层组件,注入store
  4. 组件交互(useSelector、useDispatch):通过hooks获取状态和派发action
  5. 处理异步(createAsyncThunk):通过thunk管理副作用

创建Slice

Slice是RTK的核心概念,RTK中的createSlice会自动生成action creators 和 reducer,简化了redux中需要手动编写action类型和action创建函数的过程

这里选择用一个简单的全局登录状态管理作为本文的示例:

先明确一下需求:

需要存储的只有一个登录状态(true/false)和一个token,项目运行时会有路由守卫机制检查存储中的token状态,如果没有token或者token已过期,则重定向到登录页面进行登录,用户登录后将token存在localStorae中且登录状态为true,用户登出后销毁token并将登录状态更新为false

authSlice.js

js 复制代码
import {createSlice} from '@reduxjs/toolkit'

const authSlice = createSlice({
    name:'auth'//对切片进行命名
    initialState:() => {     //赋初始状态值
    const token = localStorage.getItem('token')
    if(!token) {
        return {
            isLogged:false,
            token:null
            }
     } else {
         return {
            isLogged:true,
            token,
            }
        }
    },//这里由于特殊的需求需要进行判断返回不同的状态初值,也可以在initialState这里不返回函数而直接赋值
    reducers: {
        login(state, action) {
            state.isLogged = true
            state.token = action.payload.token
            //同时将token存到本地
            localStorage.setItem('token', state.token)
            },
         logout(state, action) {
            state.isLogged = false
            state.token = null
            //删除本地token
            localStorage.removeItem('token', state.token)
            },
        },   
})

export const {login, logout} = authSlice.actions //自动生成 action creators
export default authSlice.reducer // 导出 reducer,每个reducer对应一个同步 action

配置Store

store可以想象成一个仓库的入口,在这里对各个切片进行总的管理和集成,在与React连接时也是将store进行注入

store.js

js 复制代码
import { configureStore } from "@reduxjs/toolkit";
import  authReducer  from "./authSlice.js";

export const store = configureStore({
//这里作为store中的一个命名空间用于区分不同的 reducer
  reducer:{
    auth:authReducer, //将 authReducer 命名为 auth,在其他组件中调用时统一使用 auth 作为状态路径
  },
})
 

注意:configureStore 会默认集成Redux DevTools 扩展和默认包含redux-thunk 中间件(处理异步)

连接 React

在React挂载根组件处,使用 Provider 包裹并注入 store,使 store 全局可用

index.js

js 复制代码
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {store} from '../src/store/index'
import { Provider } from 'react-redux';

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

组件交互

当我们需要再具体组件中对状态进行更新时,还需要用到其他两个钩子: useSelector() 和 useDispatch()

如果对照官方解释,可能一时半会难以理解,但实际使用时,这两个钩子的作用简单来说就是 一取一改

  • useSelector():用来取出store中具体切片所存储的状态值
  • useDispatch():用来对具体的状态值进行更新,也就是修改

分别以路由守卫机制和登录界面逻辑做示例:

needAuth.js

js 复制代码
import React from 'react'
import { useSelector } from 'react-redux';
import { Navigate } from 'react-router-dom';

const NeedAuth =(props) => {
//利用 useSelector 取出用户当前的登录状态
  const res = useSelector( state => state.auth.isLogged);
//判断此时是否应该重定向到登录页面
  return res.isLogged ? props.children : <Navigate to={'/'} replace/>
}
export default NeedAuth;

//在路由配置中引入 NeedAuth 包裹主页面即可实现路由守卫

login.js

js 复制代码
import { useDispatch } from "react-redux";
import { login } from "./authSlice.js";

const Login = () => {
  const dispatch = useDispatch();
  const navigate = useNavigate();
  
  //登录表单提交,这里使用了antd的表单组件函数
  const onFinish = async (values) => {
          const res = await loginFetch(values) //此处默认使用封装后的登录API
          if(res.data.isSuccess) {
              dispatch(
                  login({
                      token:res.data.token
                  })
              )
          }
          //跳转主页面
          navigate('/', {replace:true})
  }
}

处理异步

在Redux中,处理异步操作通常需要使用中间件,比如redux-thunk。RTK默认集成了这些中间件,而createAsyncThunk的作用就是生成处理异步生命周期的action,简化流程。

createAsyncThunk的工作原理:

它接收一个action类型的前缀和一个返回Promise的payload创建函数。然后,它会自动生成pending、fulfilled和rejected三种action类型,我们无需手动编写这些action creators。这样减少了样板代码,提高了代码的可维护性。

使用场景:

进行API调用、异步数据获取或提交表单数据,需要处理loading、成功和错误状态的场景下。如果是简单的同步操作,则不适合使用

场景 适用性 示例
API 请求 ✅ 最佳实践 获取用户数据
表单提交 ✅ 推荐 登录/注册
简单状态更新 ⚠️ 过度设计 切换按钮状态
复杂数据转换 ✅ 适用 CSV 文件解析上传
需要取消的操作 ⚠️ 需额外配置 搜索建议请求

下面依旧使用刚才的登录状态管理作为示例,使用createAsyncThunk进行优化: authSlice.js

js 复制代码
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

// 步骤1:创建异步登录操作
export const loginUser = createAsyncThunk(
  'auth/login', // action类型前缀(自动生成三种状态:pending/fulfilled/rejected)
  async (values, { rejectWithValue }) => { // values 包含用户名和密码
    try {
      const response = await loginFetch(values);
      return response.token; // 返回的值会成为 fulfilled action 的 payload
    } catch (error) {
      return rejectWithValue(error.message); // 错误信息会传递到 rejected action
    }
  }
);

//创建切片
const authSlice = createSlice({
  name: 'auth',
  initialState: () => {
    const token = localStorage.getItem('token');
    return {
      isLogged: !!token, // 简化的布尔值转换
      token: token || null,
      loading: false,   // 新增加载状态
      error: null       // 新增错误信息
    };
  },
  reducers: {
    // 步骤2:保持登出操作为同步
    logout(state) {
      state.isLogged = false;
      state.token = null;
      localStorage.removeItem('token');
      state.error = null; // 清除可能的错误信息
    }
  },
  // 步骤3:处理异步操作的生命周期
  extraReducers: (builder) => {
    builder
      .addCase(loginUser.pending, (state) => {
        state.loading = true;
        state.error = null; // 开始新请求时清除旧错误
      })
      .addCase(loginUser.fulfilled, (state, action) => {
        state.loading = false;
        state.isLogged = true;
        state.token = action.payload;
        localStorage.setItem('token', action.payload); // 存储token
      })
      .addCase(loginUser.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload; // 显示错误信息
      });
  }
});

// 导出同步action和reducer
export const { logout } = authSlice.actions;
export default authSlice.reducer;

// 步骤4:创建选择器(可选但推荐)
export const selectIsLoggedIn = state => state.auth.isLogged;
export const selectAuthToken = state => state.auth.token;
export const selectAuthLoading = state => state.auth.loading;
export const selectAuthError = state => state.auth.error;

相比于之前的authSlice版本,这里将登录操作拆分为三个明确阶段:

  • pending: 开始登录(显示加载状态)
  • fulfilled: 登录成功(更新状态)
  • rejected: 登录失败(显示错误)

使用流程对比

场景 原版 优化版
发起登录 dispatch(login({ token })) dispatch(loginUser(values))
处理加载 手动管理 自动更新 loading 状态
错误处理 需要自行捕获 自动捕获并存储错误
本地存储 在reducer中处理 在fulfilled阶段处理

组件中使用: login.js

js 复制代码
import { useDispatch, useSelector } from 'react-redux';
import { loginUser, selectAuthLoading, selectAuthError } from './authSlice';

function LoginForm() {
  const dispatch = useDispatch();
  const loading = useSelector(selectAuthLoading);
  const error = useSelector(selectAuthError);

  const handleSubmit = (e) => {
    e.preventDefault();
    const formData = new FormData(e.target);
    dispatch(loginUser({
      username: formData.get('username'),
      password: formData.get('password')
    }));
  };

  return (
    <form onSubmit={handleSubmit}>
      {error && <div className="error">{error}</div>}
      <input name="username" disabled={loading} />
      <input name="password" type="password" disabled={loading} />
      <button type="submit" disabled={loading}>
        {loading ? '登录中...' : '登录'}
      </button>
    </form>
  );
}

供学习参考,有错误敬请指出

相关推荐
顾林海8 分钟前
Flutter Dart 运算符全面解析
android·前端
七月丶15 分钟前
🚀 现代 Web 开发:如何优雅地管理前端版本信息?
前端
漫步云端的码农17 分钟前
Three.js场景渲染优化
前端·性能优化·three.js
悬炫17 分钟前
赋能大模型:ant-design系列组件的文档知识库搭建
前端·ai 编程
用户1083863868021 分钟前
95%开发者不知道的调试黑科技:Apipost让WebSocket开发效率翻倍的秘密
前端·后端
稀土君1 小时前
👏 用idea传递无限可能!AI FOR CODE挑战赛「创意赛道」作品提交指南
前端·人工智能·trae
OpenTiny社区1 小时前
Node.js 技术原理分析系列 4—— 使用 Chrome DevTools 分析 Node.js 性能问题
前端·开源·node.js·opentiny
写不出代码真君1 小时前
Proxy和defineProperty
前端·javascript
乐坏小陈1 小时前
TypeScript 和 JavaScript:2025 年应该选择哪一个?【转载】
前端·javascript
百变小驴1 小时前
不懂脚手架怎么开发?手把手带你读create-vite源码!
前端·前端工程化