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

【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" });//每点击一次加1dispatch({ 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(iNumStatusReducer,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.mzph.cn/news/667113.shtml

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

相关文章

[AIGC] 21世纪Java与Go的相爱相杀

在21世纪的软件开发领域中&#xff0c;Java和Go这两门编程语言可谓是相爱相杀的存在。它们各自拥有着强大的特点和独特的优势&#xff0c;同时也存在着一些明显的竞争和冲突。让我们来看看这两门语言的故事&#xff0c;以及它们之间的深远意义。 文章目录 Java的魅力Go的魅力相…

C++写算法题时常见问题(稳定更新)

目录 1.如何用 getline 函数读取用户输入的一行 2.如何防止用 scanf 读取字符时读取了 换行和空格 3.map和unordered_map的差别和使用 4.“表达式求值”问题解析 5.运行报RE错误 6.在set或者map里面使用结构体 7.运行时报TLE时&#xff0c;时间复杂度问题 8.double类型的…

Photoshop CS6 下载安装教程,保姆级教程,小白也能轻松搞的,附安装包

前言 Adobe Photoshop CS6强大的照片拍摄和突破性的新功能&#xff0c;用于复杂的图形、选择、逼真的绘画和装饰智能。创建惊人的高动态范围(HDR)图像。用逼真的笔触和混合的颜色绘画。消除噪音&#xff0c;添加种子&#xff0c;并绘制一个国家最先进的摄影设备的草图。凭借原…

神经网络不需要懂原理,只需要应用???(附268篇顶会论文)

神经网络不需要弄明白原理&#xff0c;只要会应用就行&#xff0c;这是真的吗&#xff1f; 具体情况具体分析。如果你是论文要求不高&#xff0c;那么就不需要搞太清楚&#xff0c;如果你的毕业要求高&#xff0c;或者想要更高的提升&#xff0c;尤其是想申博、进大厂&#xf…

【C语言】socket编程接收问题

一、recv()函数接收到的返回值为0表示对端已经关闭 在TCP套接字编程中&#xff0c;通过recv()函数接收到的返回值为0通常表示对端已经关闭了套接字的发送部分。这是因为TCP是一个基于连接的协议&#xff0c;其中有定义明确的连接建立和终止流程&#xff1b;当对端调用close()或…

数据分析:当当网书籍数据可视化分析

当当网书籍数据可视化分析 作者&#xff1a;i阿极 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;博主个人首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f44d;收藏&#x1f4c1;评论&…

基于场景文字知识挖掘的细粒度图像识别算法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 摘要Abstract文献阅读&#xff1a;基于场景文字知识挖掘的细粒度图像识别算法1、研究背景2、方法提出方法模块 3、试验4、文章贡献 二、RNN代码学习2.1、什么是RNN2…

Mysql学习记录补充

索引 在无索引情况下&#xff0c;就需要从第一行开始扫描&#xff0c;一直扫描到最后一行&#xff0c;我们称之为 全表扫描&#xff0c;性能很低。 如果我们针对于这张表建立了索引&#xff0c;假设索引结构就是二叉树&#xff0c;那么也就意味着&#xff0c;会对age这个字段…

Linux|Grep 命令的 12 个实用示例

您是否曾经遇到过在文件中查找特定字符串或模式的任务&#xff0c;但不知道从哪里开始查找&#xff1f;那么&#xff0c;grep 命令可以拯救你&#xff01; grep 是一个功能强大的文件模式搜索器&#xff0c;每个 Linux 发行版都配备了它。如果出于某种原因&#xff0c;它没有安…

【C++入门学习指南】:函数重载提升代码清晰度与灵活性

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; C入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、函数重载1.1 函数重载的概念1.2 函数重载的作用1.3 C支持函数重载的原理1.4 扩展 &…

C++ STL库详解:容器适配器stack和queue的结构及功能

一、stack 1.1stack的介绍 1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入与提取操作。 2. stack是作为容器适配器被实现的&#xff0c;容器适配器即是对特定类封装作为其底层的容器&#xf…

图数据库(neo4j)在工业控制中的应用

图模型 事物的模型中&#xff0c;除了它自身的某些特征之外&#xff0c;还包括它与其它事物的关系特征&#xff0c;例如一个学生的属性包括姓名&#xff0c;性别&#xff0c;年龄等属性&#xff0c;同时&#xff0c;他还有许多关系属性&#xff0c;比如他属于哪一个院系&#x…

修改照片尺寸好用的工具,分享4款!

在数字时代&#xff0c;照片已成为我们生活的一部分&#xff0c;而如何调整照片尺寸以满足不同的需求&#xff0c;则显得至关重要。今天&#xff0c;我们就来探讨那些可以修改照片尺寸的工具&#xff0c;让你轻松应对各种尺寸需求。 茄子水印相机 这是一款功能强大、操作简单的…

MacBook有必要装清理软件吗?CleanMyMac X v4.14.6 直装特别版 附安装教程

MacBook是苹果公司的一款高端笔记本电脑&#xff0c;但是&#xff0c;随着使用时间的增长&#xff0c;MacBook也会出现一些问题&#xff0c;比如运行缓慢、卡顿、垃圾文件堆积、磁盘空间不足等。这些问题不仅影响了用户的使用体验&#xff0c;也可能对MacBook的寿命和安全性造成…

已经购买了阿里云服务器ECS,如何在上面部署幻兽帕鲁服务器?(一键安装非常简单)

很多人都知道阿里云可以支持一键购买并部署幻兽帕鲁服务器&#xff0c;不需要你进行任何配置&#xff0c;也不用你登录服务器&#xff0c;通过查看和管理计算巢面板就可以了&#xff0c;直接就可以开玩了。但是如果你已经有了一台阿里云服务器ECS那么该怎么去搭建幻兽帕鲁服务器…

Centos 内存和硬盘占用情况以及top作用

目录 只查看内存使用情况&#xff1a; 内存使用排序取前5个&#xff1a; 硬盘占用情况 定位占用空间最大目录 top查看cpu及内存使用信息 前言-与正文无关 生活远不止眼前的苦劳与奔波&#xff0c;它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&…

c++类继承

一、继承的规则 &#xff08;1&#xff09;基类成员在派生类中的访问权限不得高于继承方式中指定的权限。例如&#xff0c;当继承方式为protected时&#xff0c;那么基类成员在派生类中的访问权限最高也为protected&#xff0c;高于protected会降级为protected&#xff0c;但低…

通讯基本概念

通信的方式有多种&#xff0c;按数据传输方式可分为串行通讯和并行通信&#xff1b;按通信数据同步方式可分为同步通信和异步通信&#xff1b;按数据通信的方向可分为 一、串行通信和并行通信 串行通信&#xff1a;设备之间通过少量的数据信号线&#xff08;一般是8根以下&am…

STM32 自学笔记 学习笔记 一

起源&#xff0c;A7,A9,M3&#xff0c;原来弄了A9的TQ2440&#xff0c;结果还得来重新熟悉下32函数JLINK使用SW方式&#xff0c;本来可以下载&#xff0c;但是一根线掉了重新上去&#xff0c;就出各种跟线无关问题&#xff0c;干脆把32断了重新接&#xff0c;结果就成功了&…