【REACT-@reduxjs/toolkit+react-redux+redux-persist状态管理】

article/2025/10/9 14:23:57

REACT-@reduxjs/toolkit+react-redux+redux-persist状态管理

  • 1. 依赖包安装
  • 2. 目录结构
  • 3. 创建store.js 和 修改Index.js
    • 3.1 创建store.js
    • 3.2 创建修改Index.js
  • 4. createSlice()
    • 4.1 action处理
      • 4.1.1 创建collapsedSlice
      • 4.1.2 使用collapsedSlice
    • 4.2 异步action处理
      • 4.2.1 使用redux-thunk方式处理异步
        • 4.2.1.1 创建asyncReduxSlice
        • 4.2.1.2 使用asyncReduxSlice
      • 4.2.2 createAsyncThunk()支持thunk
      • 4.2.2.1 创建CATSlice
      • 4.2.2.1 使用CATSlice
  • 5. Selector使用缓存
    • 5.1 创建listFilterSlice
    • 5.1 使用listFilterSlice
  • 6. 调试工具

参考:
Redux最新实践指南之Redux-Toolkit
redux最佳实践redux-toolkit使用指南
react+ts实战之 @reduxjs/toolkit
2015年发布的Redux至今仍是React生态中最常用的状态管理库,2022年4月19日发布的Redux v4.2.0中正式将createStore方法标记为“已弃用”(@deprecated),并推荐用户使用Redux-Toolkit(下面简称为RTK)的configureStore方法。

1. 依赖包安装

npm i @reduxjs/toolkit react-redux redux-persist

2. 目录结构

在这里插入图片描述

3. 创建store.js 和 修改Index.js

3.1 创建store.js

import {configureStore, combineReducers } from '@reduxjs/toolkit'
import CollapsedSlice from './features/CollapsedSlice'
import LoadingSlice from './features/LoadingSlice';
import AsyncReduxSlice from './features/AsyncReduxSlice';
import CreateAsyncThunkSlice from './features/CreateAsyncThunkSlice';
import ListFilterSlice from './features/ListFilterSlice';
import RouterListenerSlice from './features/RouterListenerSlice';//持久化数据
import {persistStore,persistReducer,FLUSH,REHYDRATE,PAUSE,PERSIST,PURGE,REGISTER
} from 'redux-persist'
import storage from 'redux-persist/lib/storage';const reducer = combineReducers({CollapsedSlice,//相当于CollapsedSlice:CollapsedSliceLoadingSlice,RouterListenerSlice,AsyncReduxSlice,CreateAsyncThunkSlice,ListFilterSlice,
})const persistConfig = {key:'redux',storage:storage,whitelist:['CollapsedSlice'],//白名单只保存CollapsedSlice// blacklist:['CollapsedSlice'],//黑名单仅不保存CollapsedSlice
}const persistedRedcer = persistReducer(persistConfig,reducer);const store = configureStore({reducer:persistedRedcer,middleware: (getDefaultMiddleware) =>getDefaultMiddleware({serializableCheck: {//忽略了 Redux Persist 调度的所有操作类型。这样做是为了在浏览器控制台读取a non-serializable value was detected in the state时不会出现错误。ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],},})
})export const persistor = persistStore(store);export default store;

3.2 创建修改Index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import "./axios";
import { Provider } from 'react-redux';
import store,{persistor} from './redux/store'
import { PersistGate } from "redux-persist/integration/react";
// import reportWebVitals from './reportWebVitals';
// npm i -g json-server
// json-server --watch ./db.json --port 5000
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(// <React.StrictMode><Provider store={store}><PersistGate loading={null} persistor={persistor}><App /></PersistGate></Provider>// </React.StrictMode>
);// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
// reportWebVitals();

4. createSlice()

使用createSlice方法创建一个slice。每一个slice里面包含了reducer和actions,可以实现模块化的封装。所有的相关操作都独立在一个文件中完成。

4.1 action处理

4.1.1 创建collapsedSlice

CollapsedSlice.js

import { createSlice } from '@reduxjs/toolkit';const initialState = {collapsed:false
}export const collapsedSlice = createSlice({// 命名空间,在调用action的时候会默认的设置为action的前缀collapsedSlice/changeCollapsedname:'collapsedSlice',// 初始值initialState:initialState,// 这里的属性会自动的导出为collapsedSlice.actions,在组件中可以直接通过dispatch进行触发reducers:{//{ payload }解构出来的payload是dispatch传递的数据对象changeCollapsed(state,action){// console.log(action)// {//   "type":"collapsedSlice/changeCollapsed",//   "payload":{//       "value":2//   }// }// 内置了immutable不可变对象来管理state,不用再自己拷贝数据进行处理state.collapsed = !state.collapsed;}}
})// 导出actions
export const { changeCollapsed } = collapsedSlice.actions;// 导出reducer,在创建store时使用到
export default collapsedSlice.reducer;

4.1.2 使用collapsedSlice


import { useSelector, useDispatch } from 'react-redux';
import {changeCollapsed} from '../../redux/features/CollapsedSlice' // 引入actionsimport {MenuUnfoldOutlined,MenuFoldOutlined,UserOutlined,
} from "@ant-design/icons";
import React from 'react'
import { Layout, Dropdown, Avatar,Button } from "antd";
import { useNavigate } from 'react-router';
const { Header} = Layout;export default function TopHeader() {//根据store.js中设置的reducer名字,从CollapsedSlice空间获取stateconst {collapsed} = useSelector(state=>state.CollapsedSlice);const dispatch = useDispatch();const handleCollapsed = ()=>{dispatch(changeCollapsed({value:2}));}const { username, role:{roleName} } = JSON.parse(localStorage.getItem("token"));const navigate = useNavigate();const items = [{key: '1',label: roleName,},{key: '2',label: (<Button type="primary" danger onClick={() => {localStorage.removeItem("token");navigate("/login",{replace:true}); }}>退出登录</Button> ),},];return (<Header className="site-layout-background" style={{ paddingLeft: "16px" }}>{/* {React.createElement(collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {className: 'trigger',onClick: () => setCollapsed(!collapsed),})} */}{collapsed ? <MenuUnfoldOutlined  onClick={handleCollapsed}/>: <MenuFoldOutlined onClick={handleCollapsed}/>}<div style={{ display: "inline", float: "right" }}><span>欢迎<span style={{ color: "#1890ff" }}>{username}</span>回来</span><Dropdown  menu={{items}}><div style={{display:'inline-block',cursor:'pointer'}} onClick={(e) => e.preventDefault()}><Avatar size="large" icon={<UserOutlined />} /></div></Dropdown></div></Header>)
}

4.2 异步action处理

4.2.1 使用redux-thunk方式处理异步

RTK集成了redux-thunk来处理异步事件,所以可以按照之前thunk的写法来写异步请求

4.2.1.1 创建asyncReduxSlice

AsyncReduxSlice.js

import { createSlice } from "@reduxjs/toolkit";
import axios from 'axios'const initialState = {list:[]
}
export const asyncReduxSlice = createSlice({name:'asyncReduxSlice',initialState,reducers:{changeList(state,{payload}){state.list = payload.list;}}
})const {changeList} = asyncReduxSlice.actions;export const getList = payload => {return dispatch => {axios.get("/rights?_embed=children").then((res) => { dispatch(changeList({list:res.data}))});}
}export default asyncReduxSlice.reducer;

4.2.1.2 使用asyncReduxSlice

Test-AsyncRedux.js

import React, { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux/es/exports'
import {getList} from '../redux/features/AsyncReduxSlice'export default function TestAsyncRedux() {const {list} = useSelector(state=>state.AsyncReduxSlice);const dispatch = useDispatch();useEffect(()=>{console.log(111111)if(list.length === 0){dispatch(getList())}else{alert('列表已被缓存!')}},[dispatch,list.length]);return (<div>{list.map(item=>{return <li key={item.id}>{item.title}</li>})}</div>)
}

4.2.2 createAsyncThunk()支持thunk

createAsyncThunk方法可以创建一个异步的action,这个方法被执行的时候会有三个( pending(进行中) fulfilled(成功) rejected(失败))状态。可以监听状态的改变执行不同的操作。以下代码示例中使用到了extraReducers创建额外的action对数据获取的状态信息进行监听。

4.2.2.1 创建CATSlice

CreateAsyncThunkSlice.js

import {createSlice,createAsyncThunk} from '@reduxjs/toolkit'
import axios from 'axios'const getListAPI = ()=>{return axios.get("/rights?_embed=children").then((res) => res.data);
}export const loadList = createAsyncThunk('CATSlice/loadList',async ()=>{const list = await getListAPI();return list;}
)
const initialState = {list:[]
}
export const CATSlice = createSlice({name:'CATSlice',initialState,// 可以额外的触发其他slice中的数据关联改变extraReducers: builder=>{builder.addCase(loadList.pending,state=>{console.log('进行中');}).addCase(loadList.fulfilled,(state,action)=>{console.log('成功');const { payload } = action;// {//   type:'CATSlice/loadList/fulfilled',//   payload://loadList返回值// }console.log(action);state.list = payload;}).addCase(loadList.rejected,(state, err)=>{console.log('失败',err);})}
})export default CATSlice.reducer;

4.2.2.1 使用CATSlice

Test-CreateAsyncThunk.js

import React, { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux/es/exports'
import {loadList} from '../redux/features/CreateAsyncThunkSlice'export default function TestAsyncRedux() {const {list} = useSelector(state=>{console.log(state)return state.CreateAsyncThunkSlice});const dispatch = useDispatch();useEffect(()=>{console.log(11111111)if(list.length === 0){dispatch(loadList())}else{alert('列表已被缓存!')}},[]);// eslint-disable-linereturn (<div>{list.map(item=>{return <li key={item.id}>{item.title}</li>})}</div>)
}

5. Selector使用缓存

当useSelector方法涉及到复杂逻辑运算时,且返回一个对象的时候,每次运行都返回了一个新的引用值,会使组件重新渲染,即使返回的数据内容并没有改变
为了解决这个问题,可以使用Reselect库,它是一个创建记忆化selector的库,只有在输入发生变化时才会重新计算结果,rtk正是集成了这个库,并把它导出为createSelector函数

引用的CreateAsyncThunkSlice.js参照上面

5.1 创建listFilterSlice

ListFilterSlice.js

import { createSlice } from '@reduxjs/toolkit';const initialState = {listFilter:'/home'
}export const listFilterSlice = createSlice({// 命名空间,在调用action的时候会默认的设置为action的前缀listFilterSlice/changelistFiltername:'listFilterSlice',// 初始值initialState:initialState,// 这里的属性会自动的导出为listFilterSlice.actions,在组件中可以直接通过dispatch进行触发reducers:{//{ payload }解构出来的payload是dispatch传递的数据对象changelistFilter(state,action){// console.log(action)// {//   "type":"listFilterSlice/changelistFilter",//   "payload":{//       "value":2//   }// }// 内置了immutable不可变对象来管理state,不用再自己拷贝数据进行处理state.listFilter = !state.listFilter;}}
})// 导出actions
export const { changelistFilter } = listFilterSlice.actions;// 导出reducer,在创建store时使用到
export default listFilterSlice.reducer;

5.1 使用listFilterSlice

Test-CreateSelector.js

import React, { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux/es/exports'
import {loadList} from '../redux/features/CreateAsyncThunkSlice'
import { createSelector } from '@reduxjs/toolkit';//当useSelector方法涉及到复杂逻辑运算时,且返回一个对象的时候,每次运行都返回了一个新的引用值,会使组件重新渲染,即使返回的数据内容并没有改变
//为了解决这个问题,可以使用Reselect库,它是一个创建记忆化selector的库,只有在输入发生变化时才会重新计算结果,rtk正是集成了这个库,并把它导出为createSelector函数
const selectList = state=>state.CreateAsyncThunkSlice;
const selectFilter = state=>state.ListFilterSlice;const filterList = createSelector(selectList,selectFilter,(listState,filterState)=>{const {list} = listState;const {listFilter} = filterState;console.log(listState,filterState)switch(listFilter){case 'all':return list;case '/home':return list.filter(item=>item.key === listFilter);default :throw new Error('Unknown filter: ' + listFilter);}
})export default function TestAsyncRedux() {const mapList = useSelector(state => filterList(state));const dispatch = useDispatch();useEffect(()=>{console.log(11111111)if(mapList.length === 0){dispatch(loadList())}else{alert('列表已被缓存!')}},[]);// eslint-disable-linereturn (<div>{mapList.map(item=>{return <li key={item.id}>{item.title}</li>})}</div>)
}

6. 调试工具

RTK中已经配置了redux-devtools,所以只要浏览器安装调试工具redux-devtools-extension
安装参考redux-devtools-extension


http://chatgpt.dhexx.cn/article/OE3GZjAx.shtml

相关文章

detached entity passed to persist问题与解决方案

JPA save对象的时候有时候会遇到如题的错误&#xff0c;可能有两种原因&#xff1a; 1.该对象定义的是自动生成id的方式&#xff0c;insert的时候写入的id在数据库中已存在。 网上搜到的比较多的都是这种情况&#xff0c;但个人认为&#xff0c;实际项目中这么玩的情况很少&am…

谈谈Persistent属性

文章目录 1. 背景2. 开机自启动流程3. adb kill -9 杀进程后会自动重启4. 小结 1. 背景 在应用AndroidManifest文件下添加 android:persistent“true” 关键字&#xff0c;并把Apk预置到system/app目录下&#xff0c;可以给应用实现开机自启动和保活效果。 从以下两个疑问去找…

cache和persist区别

cache()是persist()的特例&#xff0c;persist可以指定一个StorageLevel(缓存级别) cache的缓存级别是memory_only 区别就是cache默认是在内存中存储的&#xff0c;而persist可以设置存储的级别&#xff1a; 如何选择一种最合适的持久化策略 默认情况下&#xff0c;性能最高…

安卓机型传感器分区故障persist的相关说明 修复步骤

手机的分区很多。有些分区刷机不管是卡刷还是底层9008刷写等等默认是不会刷写的。其中包括基带分区 persist分区等等这些。这类分区一般也不会出问题&#xff0c;当然也有个例。例如更新降级或者刷写第三方或者全部檫除分区或者格机软件等等会导致这些分区出问题。今天这个帖子…

Android Q - Signature|privileged permissions not in privapp-permissions whitelist(卡在开机logo无法开机)

简单记录下&#xff0c;我是在 launcher3 里进行修改&#xff0c;添加了几个权限后&#xff0c;替换应用正常运行&#xff0c;但是在重新编译软件时无法开机&#xff0c;Android studio 提示错误如下&#xff1a; system_process E/AndroidRuntime: *** FATAL EXCEPTION IN SYS…

Failed to get D-Bus connection: Operation not permitted一个关于--privileged=true失效并不能进入root权限的大坑

一个关于--privilegedtrue失效并不能进入root权限的大坑&#xff0c;坑了我一晚上。。。 先上连接解决这个问题 感谢这位大佬可以用 https://blog.csdn.net/zhenliang8/article/details/78330658 我的问题出在哪儿了&#xff1f; 这里并不是/bin/bash 而是/usr/sbin/init 不按…

【错误记录】手机应用无法联网 ( 添加 READ_PRIVILEGED_PHONE_STATE 权限导致手机应用网络不可用 )

文章目录 一、报错信息二、解决方案 一、报错信息 在应用的首界面 , 连接 WebSocket 服务器 , 调用了 WebSocketClient # connectBlocking() 方法 , 阻塞连接 WebSocket , 但是网络没有相应 , 导致了 ANR 异常 ; 参考 【Android WebSocket】Android 端 WebSocket 基本用法 ( 添…

k8s设置pod privileged权限(特权):securityContext.privileged=true

k8s部署es的时候需要初始化很多linux的内核参数。 但是文件系统挂载到pod容器中就会变成read-only&#xff0c;难以进行操作实现需求。 所以需要给POD privileged权限&#xff0c;然后在容器的初始化脚本或代码中去修改sysctl参数。 创建POD/deployment/daemonset等对象时&…

ARM基础(2):模式和特权等级(User/Thread mode和Privileged level)

Cortex-M3处理器支持两种模式和两种特权级别。 如下图所示&#xff0c;当处理器运行于Thread mode时&#xff0c;它可以处于Privileged或User级别&#xff1b;而Handler mode下&#xff0c;只能处于Privileged级别。当处理器复位完毕后&#xff0c;处于Thread mode。 在User级…

【云原生 | Kubernetes 系列】K8s 实战 实施Pod 容器标准的两种方式

实施Pod 容器标准的两种方式 前言一、通过名字空间标签来要求实施 baseline Pod 容器标准1.1、使用 kubectl label 为现有名字空间添加标签1.2、应用到所有名字空间1.3、应用到单个名字空间 二、通过配置内置准入控制器实施 Pod 安全标准总结 前言 上一节学习了 PodSecurity &a…

privilege_role

本文章为网络笔记&#xff0c;看了warehouse老师的视频受益匪浅&#xff0c;更是感觉自己技术太过初级&#xff0c;特写了本笔记&#xff0c;方便以后反复学习&#xff01; 如有任何不妥&#xff0c;请发邮件至102448567qq.com删除文章&#xff01; 关于warehouse&#xff1a; …

docker --privileged=true 参数作用

大约在0.6版&#xff0c;privileged被引入docker。使用该参数&#xff0c;container内的root拥有真正的root权限。否则&#xff0c;container内的root只是外部的一个普通用户权限。privileged启动的容器&#xff0c;可以看到很多host上的设备&#xff0c;并且可以执行mount。甚…

docker--privileged

一、 privilegedtrue|false 介绍 true container内的root拥有真正的root权限。 false container内的root只是外部的一个普通用户权限。默认false privileged启动的容器 可以看到很多host上的设备可以执行mount。可以在docker容器中启动docker容器。 二、测试验证 2.1、未设…

(十二)docker --privileged

1. privileged参数作用 --privileged Give extended privileges to this container 大约在0.6版&#xff0c;privileged被引入docker。使用该参数&#xff0c;container内的root拥有真正的root权限。否则&#xff0c;container内的root只是外部的一个普通用…

TDL、CDL信道模型简述

主要参考&#xff1a;3GPP TR 38.811 TDL&#xff08;Tapped Delay Line&#xff09;抽头延时线模型 TDL模型主要针对多径时延参数和反映信道时变特性的多普勒参数进行研究&#xff0c;主要有TDL-A、TDL-B、TDL-B、TDL-D、TDL-E五种。其中前三者为NLOS传输的多径信道模拟&…

无线信道模型分类和建模方法介绍--附思维导图

目录 1 统计性模型&#xff08;经验模型&#xff09;1.1 模型分类&#xff08;1&#xff09;按衰落分类&#xff08;2&#xff09;按路径损耗和延迟拓展分类&#xff08;3&#xff09;按IO数量分类 1.2 建模方法&#xff08;1&#xff09;方法一分类&#xff08;2&#xff09;方…

【S-V信道】基于毫米波的5G通信S-V信道模型仿真

1.软件版本 MATLAB2021a 2.本算法理论知识 由于大气中存在一定含量的极化氧分子和水汽&#xff08;如图3.1所示&#xff09;&#xff0c;因此毫米波在传输过程中容易被大气吸收&#xff0c;从而导致信号衰减&#xff0c;影响通信质量[13,14]。根据相关研究发现&#xff0c;在…

m无线通信信道matlab仿真,包括自由空间损耗模型,Okumura-Hata模型,COST231 Hata模型,SUI信道模型

目录 1.算法概述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法概述 无线信道是移动通信的传输媒体&#xff0c;所有的信息都在这个信道中传输。信道性能的好坏直接决定着人们通信的质量&#xff0c;因此要想在有限的频谱资源上尽可能地高质量、大容量传输…

3GPP LTE/NR信道模型

LTE三种典型信道模型&#xff1a; EPA(Extended Pedestrian A)&#xff1a;扩展步行信道模型 EVA(Extended Vehicular A)&#xff1a;扩展车辆信道模型 ETU(Extended Typical Urban)&#xff1a;扩展典型城市信道模型 EPA EVA ETU Excess tap delay [ns] Relative power…

无线通信与编码_MATLAB仿真实现Jakes信道模型_含仿真代码_瑞利衰落信道模型

1、Jakes模型简介 1.1 Rayleigh衰落信道 瑞利分布&#xff1a;当一个随机二维向量的两个分量呈独立的、均值为0、有着相同的方差的正态分布时&#xff0c;这个向量的模呈瑞利分布。 瑞利分布的概率密度函数如下&#xff1a; 瑞利衰落信道是一种无线电信号传播环境的统计模型…