【React】redux状态管理、react-redux状态管理高级封装模块化

news2024/10/7 6:47:31

【React】react组件传参、redux状态管理

  • 一、redux全局状态管理
    • 1、redux概述
    • 2、redux的组成
      • 1.1 State-状态
      • 1.2 Action-事件
      • 1.3 Reducer
      • 1.4 Store
    • 3、redux入门案例
      • 1.1 前期准备
      • 1.2 构建store
        • 1.2.1 在src下新建store文件夹
        • 1.2.2 在store文件夹下新建index.ts文件
        • 1.2.3 在index.ts文件里编写redux核心代码
        • 1.2.4 在store文件夹下新建reducer.ts文件
        • 1.2.5 在index.ts文件中引入reducer.ts
        • 1.2.6 到根目录下的入口文件index.ts文件导入store仓储对象
      • 1.3 在组件中使用store
  • 二、react-redux状态管理高级封装模块化
    • 1、在store文件夹下新建NumStatus文件夹(管理num的模块)
    • 2、在NumStatus文件夹下新建index.ts和reducer.ts文件
    • 3、如果还有其他的状态需要管理,如新建ArrStatus文件夹(管理数组模块)
    • 4、在index.ts文件中引入reducer.ts
    • 5、在组件中使用store
    • 6、模块化结束

一、redux全局状态管理

1、redux概述

  • redux是一个JavaScript容器,用于进行全局的状态管理;
  • redux三大核心;
    • 单一数据源头:所有state都会被挂载到一个叫Object tree中,Object tree又只存在唯一的Store(理解为容器,存储Object tree,Object tree挂在state)中;
      在这里插入图片描述

    • State是只读的:唯一改变state的方法就是触发action,触发action,store.dispatch ( {type: '字符串' , val: 1}),val自定义

    • 使用纯函数来执行修改:编写reducers,接受state和action,并返回一个新的state;

2、redux的组成

1.1 State-状态

  • 就是我们传递的数据,后端返回的数据、决定ui展示的状态等等;

1.2 Action-事件

  • Action是把数据从应用传到store的载体(对象),它是store数据的唯一来源,一般来说,我们可以通过store.dispatch()将action传递给store;
    在这里插入图片描述
  • Action的特点
    • Action的本质就是一个javaScript的普通对象;
    • Action对象内部必须要有一个type属性来表示要执行的动作多数情况下,这个type会被定义成字符串常量;
    • 除了type字段之外,action的结构随意进行定义;
    • 而我们在项目中,更多的喜欢用action创建函数(就是创建action的地方);
    • 只是描述了有事情要发生,并没有描述如何去更新state;
// Action创建函数
function addAction(params){
	//返回一个Action对象
	return {
		type:'add',//add为自定义
		...params
	}
}

1.3 Reducer

  • Reducer本质就是一个函数,它用来响应发送过来的actions,然后经过处理,把 state发送给Store的;
  • 在Reducer函数中,需要return返回值,这样Store才能接收到数据;
  • 函数会接收两个参数,第一个参数是初始化 state,第二个参数是action;
const initState={...}
function reducer(state=initState,action){
	return {...}
}

在这里插入图片描述

1.4 Store

//构建store
import { createstore } from "redux";
//构建store对象
const store = createstore(传递reducer) ;
  • Store 就是把action 与reducer联系到一起的对象;
  • 主要职责:
    • 维持应用的state
    • 提供getState()方法获取state
    • 提供dispatch()方法发送action
    • 通过subscribe()来注册监听
    • 通过subscribe()返回值来注销监听

3、redux入门案例

1.1 前期准备

  • 打开VSCode终端
  • 新建项目,输入npx create-react-app + 项目名称(自定义,注意最好不要中文)
  • 删除多余的配置文件,只留下(App.css,App.js,index.js)并清除三个文件下不必要的代码
  • 进入新的项目文件夹
  • 安装redux相关依赖
npm i react-redux
npm i redux
//异步解决方案redux-thunk
npm i redux-thunk
//持久化redux
npm i redux-persist
  • npm run start启动项目

1.2 构建store

1.2.1 在src下新建store文件夹
1.2.2 在store文件夹下新建index.ts文件
1.2.3 在index.ts文件里编写redux核心代码
//创建一个仓储对象,需要reducer作为对象
//本来是这么写的
import { createStore} from 'redux'
//但是改版之后,需要写成下面这个样子
import { legacy_createStore} from 'redux'
1.2.4 在store文件夹下新建reducer.ts文件
//用来管理数据的
const initData={
num :20
}
// state是状态数据的原始值,action={type : "add " ,data:{}
function reducer(state=initData,action){
	//!!!!不能操作修改旧的数据
	//不能直接修改老的状态数据,应该根据老的状态数据,生成一个新的状态数据,然后返回
	const newState=JSON.parse(JSON.stringify(state))
	switch(action.type){
		case "add1":
			newState.num++
			break;
		case "add2":
			newState.num+=action.valbreak;
			break;
		default:
			break;
	}
	return newState;
}
export default reducer
1.2.5 在index.ts文件中引入reducer.ts
//创建一个仓储对象,需要reducer作为对象
import {legacy_createStore,applyMiddleware}from ' redux';
import reduxThunk from 'redux-thunk'
import { persistStore, persistReducer } from "redux-persist";//持久化
import storage from "redux-persist/lib/storage";
import reducer from './reducer ';
const persistConfig = {
   key: "xxx",
   storage: storage,
   // whitelist:['LoadingReducers'],//想持久化哪个
};
const persistReducers = persistReducer(persistConfig, reducer )
const store = legacy_createStore(persistReducers, applyMiddleware(reduxThunk))
let persisttore = persistStore(store)
export  { store, persisttore }
1.2.6 到根目录下的入口文件index.ts文件导入store仓储对象
  • 将store与项目挂钩,导入store仓储对象
//这里可能还引入其他东西,为了简洁,我就不写了
...
//状态管理
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
//持久化
import { PersistGate } from "redux-persist/lib/integration/react";
import {store,persisttore} from "@/store";
import App from "./App" ;
ReactDOM.render(
// 将仓储对象传递给根组件
 <Provider store={store}>
  	<PersistGate persistor={persisttore}>
       <App />
  	 </PersistGate >
  </Provider>,
document.querySelector( "#root")
);

1.3 在组件中使用store

  • 通过useselector获取仓库数据
import { useDispatch, useSelector } from "react-redux";
const View = () => {
  // 通过useSelector获取仓库数据
  const { num } = useSelector((state: { num: any }) => ({ num: state.num }));
  // 通过useDispatch修改仓库的数据
  const dispatch = useDispatch();
  const changeNum = () => {
    // dispatch ( {type: '字符串' , val: 1}),val自定义
    //同步的写法
    dispatch({ type: "add1" });//每点击一次加1
    dispatch({ type: "add2" ,val:10});//每点击一次加10
   // 异步的写法:dispatch ( 异步执行的函数)
    dispatch((dis:Function)=>{
   		 setTimeout(()=>{
   			 dis({ type: "add1" })
    	},1000)
    })
  };
  return (
    <div className="home">
      <p>这是Page1页面内容</p>
      <p>{num}</p>
      <button onClick={changeNum}>按钮</button>
    </div>
  );
};
export default View;

二、react-redux状态管理高级封装模块化

  • 封装的目的:最终是有利于我们的开发或者维护
  • 封装的思路:将来开发的时候只需要把数据和方法写入到这个状态文件中,例如:XxxxStatus/index.ts,而不需要再去操作其他的文件。
    在这里插入图片描述

1、在store文件夹下新建NumStatus文件夹(管理num的模块)

2、在NumStatus文件夹下新建index.ts和reducer.ts文件

//index.ts
const store: any = {
    state: {
        isLoading: false
    },
    actions: {
    	//只放同步的方法
		add1(newState:{num:number} ,action:{type : string}){
				newstate.num++,
			}
		add2(newstate:{num: number},action:{type: string,val:number}){
				newState.num+=action.val,
			},
    },
    asyncActions: {
      //react-redux的异步解决方案redux-thunk
      //只放异步的方法
	  //优化redux-thunk的异步写法(模仿vuex的写法)
		asyncAdd1(dispatch: Function){
			setTimeout(()=>{
				dispatch({type: "add1"})
			},1000)
		},
    },
    // 名字统一管理
    actionNames: {
    }
}
//定义一个全局
let actionNames: any = {}
for (let key in store.actions) {
    actionNames[key] = key
}
store.actionNames = actionNames
export default store

//reducer.ts
//处理数据
import handle from "./index"
let reducer = (state = { ...handle.state }, action: { type: string}) => {
    let newState = JSON.parse(JSON.stringify(state))
    for (let key in handle.actionNames) {
        if (action.type === handle.actionNames[key]) {
            handle.actions[handle.actionNames[key]](newState, action)
            break;
        }
    }
    return newState
}
export default reducer

3、如果还有其他的状态需要管理,如新建ArrStatus文件夹(管理数组模块)

  • 在ArrStatus文件夹下新建index.ts和reducer.ts文件
  • index.ts内容如下
//处理数据
const store ={
state:{
	sarr:[10,20,30]
},
actions:{
	sarrpush(newState:{sarr:number[},action:{type:string, val:number})(
	newstate.sarr.push(action.val)
	}
},   
 asyncActions: {
      //只放异步的方法
    },
    // 名字统一管理
  actionNames: {
    }
}
//定义一个全局
let actionNames: any = {}
for (let key in store.actions) {
    actionNames[key] = key
}
store.actionNames = actionNames
export default store

  • reducer.ts内容都是 一样的

总结,不同的模块只有state和action里的内容,其他都一样

4、在index.ts文件中引入reducer.ts

  • 引入reducer.ts,combineReducers组合各个模块的reducer
//创建一个仓储对象,需要reducer作为对象
import {legacy_createStore,combineReducers,applyMiddleware}from ' redux';
import reduxThunk from 'redux-thunk'
import { persistStore, persistReducer } from "redux-persist";//持久化
import storage from "redux-persist/lib/storage";
import NumStatusrReducer from "./NumStatus/reducer"
import ArrstatusReducer from "./Arrstatus/reducer"
//组合各个模块的reducer
const reducers = combineReducers(i
   NumStatusReducer,
   ArrstatusReducer
})
const persistConfig = {
   key: "xxx",
   storage: storage,
   // whitelist:['LoadingReducers'],//想持久化哪个
};
const persistReducers = persistReducer(persistConfig, reducers)
const store = legacy_createStore(persistReducers, applyMiddleware(reduxThunk))
let persisttore = persistStore(store)
export  { store, persisttore }

5、在组件中使用store

  • 通过useselector获取仓库数据,跟1.3一样,唯一不一样的就是获取state不一样了
  // 通过useSelector获取仓库数据
  const { num } = useSelector((state: { num: any }) => ({ num: state.NumStatusReducer.num }));

6、模块化结束

总结

  • 不同的模块只有state和action里的内容,其他都一样;
  • 相同模块下如果需要添加同步方法,则只需在index.ts文件添加方法,在对应的组件内部调用dispatch("add3")即可
  actions: {
		add1(newState:{num:number} ,action:{type : string}){
				newstate.num++,
			}
		add2(newstate:{num: number},action:{type: string,val:number}){
				newState.num+=action.val,
			},
		add3(){
		....
		}
    },
  • 相同模块下如果需要添加异步方法,则只需在index.ts文件添加方法,在对应的组件内部调用dispatch(调用状态管理中的asyncAddx),即dispatch(state.NumStatusReducer.asyncAdd2)
   asyncActions: {
		asyncAdd1(dispatch: Function){
			setTimeout(()=>{
				dispatch({type: "add1"})
			},1000)
		 },
     asyncAdd2(){}
 },
    ```

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1434354.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用的到的linux-删除文件-Day3

前言&#xff1a; 上一节&#xff0c;我们讲到了怎么去移动文件&#xff0c;其中使用到两大类的脚本命令即cp和mv。各两种命令都可以完成移动&#xff0c;但是cp是复制粘贴的方式&#xff0c;可以选择原封不动的复制粘贴过来&#xff0c;即不修改文件及文件夹的创建时间等&…

SSH免密切换服务器案例-ssh协议(公钥和私钥)

公钥和私钥理解 公钥提供加密&#xff0c;私钥解密&#xff0c;公钥可以共享&#xff0c;私钥不可以。举例公钥相当于锁头&#xff0c;可以给别人用&#xff0c;钥匙相当于私钥&#xff0c;只能开自己发出去的锁头&#xff0c;也就是私钥和公钥成对&#xff0c;私钥只能解密对…

如何做报表? 如何建立指标体系

如何制作报表呢&#xff1f; 通过下面5步来制作报表。 如何建立指标体系? 很多数据分析招聘的要求里会写“构建指标体系”&#xff0c;所以建立指标体系是数据分析人员的一项基本技能。下面从4个问题出发&#xff0c;系统介绍指标体系&#xff1a; &#xff08;1&#xf…

编译器的实用调试技巧

目录 一. 什么是bug 二.调试的基本步骤 三.Debug和Release 四.常用快捷键 注意&#xff1a;如果你的快捷键被系统占用&#xff0c;那么可以尝试用&#xff1a;FN快捷键 F10和F11的区别 &#xff1a; F5和F9配合使用 五.如果要观察某个成员 六.断点的使用 F5和F9配合…

【Gephi项目实战-带数据集】利用gephi绘制微博肖战超话120位用户关系图,并计算整体网络指标与节点指标

数据集在评论区&#xff0c;B站演示视频在评论区&#xff01; 简介 最近2天需要用到gephi做社会网络分析&#xff0c;于是从0开始接触gephi并摸索出了gephi的基本使用指南。下面将结合真实的节点文件与边文件&#xff0c;利用gephi绘制社会网络并计算相关测量指标。整个过程会…

BC1.2 SDP/CDP/DCP介绍

参考&#xff1a;文章链接 Microchip Lightning Support 问题 Q1.) 在Microchip产品的数据表中提到了电池充电技术&#xff0c;但以下术语是什么意思: BC1.2? SDP? CDP? DCP? “SE1”? Q2.) 如何配置Microchip Hub以启用这些功能&#xff1f; Q3.) 如何在我的硬件上物…

Profinet转CANopen主站网关与堡盟编码器通讯案例

Profinet转CANopen主站网关(XD-COPNm20)为CPU与堡盟编码器的通讯提供了CANopen协议向Profinet协议转换互通的桥梁。CANopen是一种基于CAN总线的通讯协议&#xff0c;它被广泛应用于工业自动化领域&#xff0c;而Profinet是一种以太网协议&#xff0c;其优点是高速传输和广泛的可…

python-题库篇-数学

文章目录 求最大公约数和最小公倍数斐波那契数列求和运算求前n阶乘的和求年龄 求最大公约数和最小公倍数 两个数的最大公约数是两个数的公共因子中最大的那个数&#xff1b;两个数的最小公倍数 则是能够同时被两个数整除的最小的那个数。 输入&#xff1a;&#xff08;120 和…

Vue-easy-tree封装及使用

1.使用及安装 下载依赖 npm install wchbrad/vue-easy-tree引入俩种方案 1.在main.js中引入 import VueEasyTree from "wchbrad/vue-easy-tree"; import "wchbrad/vue-easy-tree/src/assets/index.scss" Vue.use(VueEasyTree)2.当前页面引入 import VueEa…

红队渗透靶机:LORD OF THE ROOT: 1.0.1

目录 信息收集 1、arp 2、nmap 3、knock 4、nikto 目录探测 1、gobuster 2、dirsearch WEB sqlmap 爆库 爆表 爆列 爆字段 hydra爆破 ssh登录 提权 信息收集 内核提权 信息收集 1、arp ┌──(root㉿ru)-[~/kali] └─# arp-scan -l Interface: eth0, ty…

Redis(三)主从架构、Redis哨兵架构、Redis集群方案对比、Redis高可用集群搭建、Redis高可用集群之水平扩展

转自 极客时间 Redis主从架构 redis主从架构搭建&#xff0c;配置从节点步骤&#xff1a; 1、复制一份redis.conf文件2、将相关配置修改为如下值&#xff1a; port 6380 pidfile /var/run/redis_6380.pid # 把pid进程号写入pidfile配置的文件 logfile "6380.log" …

使用代理IP有风险吗?如何安全使用代理IP?

代理IP用途无处不在。它们允许您隐藏真实IP地址&#xff0c;从而实现匿名性和隐私保护。这对于保护个人信息、绕过地理受限的内容或访问特定网站都至关重要。 然而&#xff0c;正如任何技术工具一样&#xff0c;代理IP地址也伴随着潜在的风险和威胁。不法分子可能会滥用代理IP…

【计算机学院寒假社会实践】——走进社区,共建美好家园

为了加强社区基层党组织建设和改进社区工作&#xff0c;推动更多资源向社区倾斜&#xff0c;曲阜师范大学计算机学院“青年扎根基层&#xff0c;服务走进社区”实践队员饶子恒在2024年1月27日来到了山东省菏泽市郓城县唐塔社区&#xff0c;对社区卫生进行清洁工作。 图为实践队…

pdf高亮显示

现在前端pdf需求越来越多&#xff0c;比如发票的显示&#xff0c;文件的显示&#xff0c;怎么实现具体步骤百度一下吧&#xff0c;这里不做详细介绍&#xff0c;主要记录下遇到的问题 1.页面pdf已经看到了&#xff0c;但是 iframe.contentWindow.PDFViewerApplication显示unde…

Python中的while循环,知其然知其所以然

文章目录 while循环结构1.用循环打印1 ~ 100步骤解析2. 1 ~ 100的累加和3.死循环1. 用死循环的方法实现 1 ~ 100累加和 4. 单向循环(1)打印 一行十个小星星*(2)通过打印一个变量的形式,展现一行十个小星星(3)一行十个换色的星星 ★☆★☆★☆★☆★☆(4)用一个循环,打印十行十列…

JAVA中的object类

一、equals方法 1.和equals的比较 既可以判断基本类型有可以判断引用类型 如果判断基本类型&#xff0c;判断的值是否相等 int num1 10; double num2 10.0; System.out.println(num1 num2); 如果判断引用类型&#xff0c;判断的地址是否相等&#xff0c;即判断是不是同一…

【教程】一个比较良心的C++代码混淆器

这是一个比较良心的C代码混淆器&#xff0c;用于信息竞赛训练和保护代码免受抄袭。本文将介绍这个混淆器的使用方法、混淆效果和已知的一些bug。同时&#xff0c;我们也会给出一些示例来演示混淆器的具体操作。 引言 在信息竞赛训练和实际开发中&#xff0c;保护代码的安全性和…

HomeAssistant系统添加HACS插件商店与远程控制家中智能家居

文章目录 基本条件一、下载HACS源码二、添加HACS集成三、绑定米家设备 ​ 上文介绍了如何实现群晖Docker部署HomeAssistant&#xff0c;通过内网穿透在户外控制家庭中枢。本文将介绍如何安装HACS插件商店&#xff0c;将米家&#xff0c;果家设备接入 Home Assistant。 基本条件…

leetcode(滑动窗口)3.无重复字符的最长字串(C++详细题解)DAY2

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示…

基于Vue2用keydown、keyup事件实现长按键盘任意键(或组合键)3秒触发自定义事件(以F1键为例)

核心代码 <template></template> <script> export default {created() {//监听长按快捷键addEventListener("keydown", this.keydown);addEventListener("keyup", this.keyup);},destroyed(d) {//移除长按快捷键removeEventListener(&…