【React】状态管理 Context API \ MobX \ Redux

  • Context API
  • MobX
  • Redux

React有自己状态管理,周边生态也有很多状态管理

Context API

直接从react中引入并调用即可,context包含两个东西:

Provider:提供商(翻译),提供数据;属性:value={提供商需要提供的数据}<Provider value={}>组件内容</Provider>Consumer:消费者(翻译),使用数据;内部是函数<Consumer>{(value)=>{ return 组件内容 }}</Consumer>

测试Context:

import {Component} from 'react'
import {createContext} from 'react' //引入react自带的状态管理,得先创建它之后才可以去用
const {Provider,Consumer}=createContext(); //用于创建一个上下文class Child extends Component {render () {return (<div><h1>儿子</h1><Child2/></div>)}
}class Child2 extends Component {render () {return (//使用时包裹起来,标明身份,Consumer内部是个函数<Consumer>{(value)=>{return <h1>孙子,使用Provider提供的数据:{value.a}</h1>}}</Consumer>/*<div><h1>子组件2</h1></div>*/)}
}class Parent extends Component {render () {return (//使用时包裹起来,标明身份,Provider不要忘记value属性<Provider value={{a:1}}><h1>父组件</h1><Child/></Provider>/*<div><h1>父组件</h1><Child/></div>*/)}
}export  default Parent;

src\App.js

import './App.css';
import Routers from './router'
// import Parent from "./pages/home/context/myclass";
import ContextAPI from './store/index';function App() {return (<div className="App"><ContextAPI><Routers/></ContextAPI>{/*<Parent/>  /!*状态管理 - 理解Context*!/*/}</div>);
}export default App;

创建公共数据组件:src\store\index.js

import {Component,createContext} from 'react'const {Provider,Consumer}=createContext();class ContextAPI extends Component {constructor() {super();this.state = {a:1,b:2}}setA=(v)=>{this.setState({a:v,});}setB=(v)=>{this.setState({b:10,});}render() {return <Provider value={{ /*value通过这个属性能够对外提供公共的数据*/state:this.state,setA:this.setA,setB:this.setB}}>{this.props.children} {/*展示ContextAPI组件中间的子组件内容的*/}</Provider>}
}export default ContextAPI;
export {Consumer}; //导出使用者:Consumer

使用公共状态:src\pages\home\notice\index.js

import {Consumer} from '../../../store/index';const Notice = () => {return <Consumer>{(value)=>{console.log(value)return <div><h1>Notice</h1><h2>a:{value.state.a}</h2>  {/*使用提供者(公共组件)的数据*/}<h2>b:{value.state.b}</h2><button onClick={()=>{value.setA(25);  /*调用提供者共享出来的方法*/value.setB();}}>修改数据</button></div>}}</Consumer>/*return <div><h1>Notice</h1></div>*/
}export default Notice;

总结:

1)创建公共数据的组件,设置数据和修改数据的方法并导出2)将该组件包裹住最大的组件,所有的组件都可以获取到公共组件的数据了2.1)公共组件需要设置 {this.props.children} 才能展示包裹住的组件的内容2.2)不能在使用公共数据的组件里面自己重新创建 const {Consumer}=createContext()因为重新创建的Consumer和我们之前在公共组件中的 Consumer 不是同一个对象3)哪个组件要使用公共数据就引入import {Consumer} from "../../../store";参考:notice -> index_context.js

MobX

mobx分两部分:

mobx:mobx语法
mobx-react:更新react的虚拟dom,把mobx和react连接起来

安装:安装 mobx 和 mobx-react 或 mobx-react-lite;mobx-react 和 mobx-react-lite 都是连接 react 和mobx的中间件,区别是:mobx-react支持类和函数组件,体积相对而言较大;而mobx-react-lite只支持函数组件,体积较小,可以根据具体情况进行下载

npm i mobx mobx-react --save语法参考:<!-- https://mobx.js.org/README.html --><!-- https://github.com/mobxjs/mobx -->

引入:

import { makeAutoObservable } from "mobx"  //makeAutoObservable:使自动可观察
import { observer } from "mobx-react-lite"  //observer:观察者

使用mobx,创建store类,并实例化导出以供使用:src\store\index.js(class写法)

import { makeAutoObservable } from "mobx"  //使自动可观察(可观测的)
// import { observer } from "mobx-react-lite"  //观察者class Store {constructor() {makeAutoObservable(this); //统一所有的this指向的固定写法}//定义数据a=1;b=2;//定义方法setA(v){this.a=v;}setB(){this.b=22;}//计算属性get c(){    //添加计算属性通过get关键词实现return this.a+this.b;}}//实例化并导出
const store=new Store();
export default store;

mobx的函数组件的写法:

import { makeAutoObservable } from "mobx"
import moduleMobx from './moduleMobx'  //引入子模块const store=()=>{return makeAutoObservable({//...moduleMobx   //在组件上使用数据的时候写法就是:store.dmoduleMobx,      //store.moduleMobx.d//定义数据a:1,b:2,//定义方法setA(v){this.a=v;},setB(){this.b=22;},//计算属性get c(){    //添加计算属性通过get关键词实现return this.a+this.b;}})}export default store();

模块化:src\store\moduleMobx.js

 const moduleMobx={ //直接导出notice.js需要使用的数据d:6,e:5,get dxe(){return this.d*this.e;},setD(v){this.d=v;}}export default moduleMobx;/*
如果直接:export default {}会出现黄色警告:Assign object to a variable before exporting as module default  import/no-anonymous-default-export
*/

使用mobx-react,observer包裹组件:src\pages\notice\index.js

import store from '../../../store';  //哪个组件需要用到store的数据就在哪个组件引入
import {observer} from 'mobx-react';  //观察者,被它包裹的组件就是响应式的,改了数据页面就会更新const Notice = () => {return <div><h1>Notice</h1>{/*使用子模块*/}<div>d:{store.moduleMobx.d}</div><div>e:{store.moduleMobx.e}</div><div>计算属性d*e:{store.moduleMobx.dxe}</div><button onClick={()=>{store.moduleMobx.setD(20)}}>修改</button><hr/>{/*没有使用子模块*/}<div>a:{store.a}</div><div>b:{store.b}</div><div>计算属性c:{store.c}</div><button onClick={()=>{store.setA(18);}}>修改</button></div>}export default observer(Notice);

总结:

1)store文件中引入:import { makeAutoObservable } from "mobx" //可观测的2)constructor() {makeAutoObservable(this); //统一所有的this指向的固定写法}3)实例化store,并导出store4)需要使用的组件引入store5)引入observer:import {observer} from 'mobx-react' //被它包裹的组件就是响应式的,改了数据页面就会更新6)将observer包裹当前组件:export default observer(Notice)7)页面使用:<div>{store.a}</div>

计算属性:

类似 Vuex 的 getter(c值:c=a+b,当a或b发生变化的时候,我希望c同步变化,就需要用到计算属性)在Mobx中添加计算属性通过get关键词实现:get 方法名(){return 干啥;}

模块化:

export default {  //直接导出component.js需要使用的数据数据}import moduleMobx from './moduleMobx'  //引入子模块moduleMobx,    //组件使用时:store.子模块名.d

Redux

参考网址:

Redux :https://cn.redux.js.org/introduction/getting-started/Redux Toolkit :https://toolkit.redux.js.cn/api/createSliceReact Redux :https://react-redux.js.org/tutorials/quick-start

特点:

1) 单一数据源:整个应用的状态存储在一个单一的对象树,且该对象树只存储在一个store中2) State是只读的:状态是不可直接修改的,改变内部状态的唯一方法是dispatch一个action3) 使用纯函数来完成状态变更:通过reducer将旧state和actions联系在一起,并返回一个新的state,不产生任何副作用

在这里插入图片描述

安装依赖:

npm i @reduxjs/toolkit react-redux //@reduxjs/toolkit 是 Redux Toolkit 的核心库,包含了创建 Redux 状态管理逻辑的工具
//react-redux 是连接 React 和 Redux 的桥梁

创建 Redux Store: store\index.js
configureStore 是 @reduxjs/toolkit 提供的函数,自动集成了 Redux DevTools 和一些默认的中间件(如 thunk)。reducer 是状态管理的核心

//Redux状态管理(使用的是:Redux Toolkit+ react-redux)
import {configureStore} from '@reduxjs/toolkit';
import counterReducer from './counterSlice';   //可以创建多个slice切片(类似于模块化)
import noticeReducer from './noticeSlice'//配置 store
const store=configureStore({reducer:{//注册子切片(将reducer添加到store中)counter:counterReducer,notice:noticeReducer,}
})export default store;

创建 Slice: store\counterSlice.js
Slice 是 Redux Toolkit 中的概念,集成了 action creators 和 reducer 的定义,便于模块化管理。每个 slice 通常代表应用中的一部分状态
createSlice 自动生成 action types 和 action creators。状态更新使用 Immer 实现,可以直接“修改” state,而无需手动展开对象

import {createSlice} from "@reduxjs/toolkit";//定义一个counter slice (slice:切片)
const counterSlice=createSlice({name: "counter", //slice的名称(模块名称独一无二)//初始化stateinitialState: {value:25,  //初始状态},//修改数据的同步方法reducers:{addNumber:(state)=>{state.value += 1; //直接修改state(内置了Immer,无需手动返回新状态)},reduceNumber:(state)=>{state.value -= 1;},numberByAmount:(state,action)=>{state.value += action.payload; //action.payload是传递的参数}}
})//导出 action creators(解构出动作创作者函数)
export const {addNumber,reduceNumber,numberByAmount} = counterSlice.actions;//导出 reducer
export default counterSlice.reducer;

将 Store 接入 React: src\index.js
在项目的入口文件(比如 src/index.js 或 src/main.js)中,使用 react-redux 的 Provider 将 Store 提供给整个应用

import React from 'react';
import ReactDOM from 'react-dom/client';
// 导入store
import store from './store';
// 导入store提供组件Provider
import { Provider } from 'react-redux';
import './index.css';
import App from './App';
import {HashRouter} from "react-router-dom";const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Provider store={store}> {/*包裹起来,提供store数据*/}<HashRouter><App /></HashRouter></Provider>);

在组件中使用 Redux: src\pages\home\notice\index.js
在 React 组件中,可以通过 react-redux 提供的 Hooks(如 useSelector 和 useDispatch)来访问状态和分发 action。useSelector 用于从 Store 中读取状态,useDispatch 用于触发 action。性能优化:如果你的组件因状态变化频繁重渲染,可以结合 useSelector 的第二个参数(比较函数)或 Redux Toolkit 的 createSelector 来优化选择器

import {useSelector,useDispatch} from "react-redux";
import {addNumber,reduceNumber,numberByAmount} from "../../../store/counterSlice";
import {fetchData,twoAsync} from "../../../store/noticeSlice";const Notice = () => {//获取状态const count=useSelector(state => state.counter.value);const adminData=useSelector(state=>state.notice.adminDate)const status=useSelector(state=>state.notice.status);//获取dispatch函数const dispatch=useDispatch();return <div><h1>Notice</h1><h1>计数器:{count}</h1><button onClick={()=>dispatch(addNumber())}>1</button><button onClick={()=>dispatch(reduceNumber())}>1</button><button onClick={()=>dispatch(numberByAmount(3))}>3</button><h1>异步处理</h1><buttononClick={()=>dispatch(fetchData())}disabled={status==="loading"}style={{color: status==="failed"?'red':'green'}}>异步fetchData</button>{JSON.stringify(adminData)}<button onClick={()=>dispatch(twoAsync({age:25,name:"lmy"}))}>异步2</button></div>}export default Notice;

异步操作: store\noticeSlice.js
如果需要处理异步逻辑,可以使用 @reduxjs/toolkit 内置的 createAsyncThunk,然后在 createSlice 中通过 extraReducers 处理异步状态

createAsyncThunk: 该函数有两个参数,一个字符串,用作生成的action types的前缀;一个payload creator回调函数,应该返回一个Promise。这通常使用async/await语法编写,因为async函数会自动返回一个Promise。createAsyncThunk函数生成一个 pending/fulfilled/rejected 基于该Promise分派动作类型的thunk。默认redux不能在reducers中处理异步,而在外部处理或者使用自带的一个方法createAsyncThunk;createAsyncThunk可以被认为是一个action,只不过它是异步的。进而正常通过dispatch派发即可;但是提到异步,就免不了有状态产生(pending/fulfilled/rejected),所以结果并不能被reducers正常归纳处理

import http from "../utils/http"; //使用自己封装的fetch
import {createSlice,createAsyncThunk} from "@reduxjs/toolkit";//1.定义异步action
export const fetchData=createAsyncThunk("notice/fetchData",async ()=>{const response=await http({url:"/admin/getadmin"}).then(res => {console.log(res);return res;})await new Promise(resolve => setTimeout(resolve, 2000)); //等待 2 秒return response.data;})//3.多个异步
export const twoAsync=createAsyncThunk("notice/twoAsync",async (obj)=>{await new Promise(resolve => setTimeout(resolve,2000));return obj;})const noticeSlice=createSlice({name: "notice",initialState: {adminDate: undefined,status:"idle",error: null,},reducers: {// ... 同步 reducers},//2.然后在createSlice中处理异步的reducer,通过extraReducers处理异步状态extraReducers:(builder)=>{builder.addCase(fetchData.pending, (state)=>{ //action被发出,但是还没有最终的结果state.status="loading";console.log("待定pending")}).addCase(fetchData.fulfilled, (state, action)=>{ //获取到最终的结果(有返回值的结果)state.adminDate=action.payload;console.log(state.adminDate)state.status="succeeded";console.log("已完成fulfilled")}).addCase(fetchData.rejected, (state, action)=>{ //执行过程中有错误或者抛出了异常state.status='failed';state.error = action.error.message; console.log("已拒绝rejected:",state.error) })//4.多个异步.addCase(twoAsync.fulfilled, (state, {payload})=>{console.log(payload)})}
})export default noticeSlice.reducer;

参考:https://blog.csdn.net/qq_34645412/article/details/144982492
React 18 与 Redux 的结合主要依赖 @reduxjs/toolkit 和 react-redux。通过 configureStore 创建 store,用 Provider 提供给组件树,然后在组件中使用 hooks(如 useSelector 和 useDispatch)来操作状态。通过以上步骤,就可以在 React 项目中成功使用 @reduxjs/toolkit 来管理状态了 (注意:Redux Toolkit 本身与 React 版本无关,React-Redux 对 React 通常会有自己的版本要求)

在这里插入图片描述

在Redux Toolkit出现之前,开发Redux应用通常涉及以下几个步骤:
状态管理目录:
在这里插入图片描述

步骤:(建议使用 Redux Toolkit 来编写代码,因为它能简化你的代码的同时消除许多常见的 Redux 问题和 Bug)

1.定义 Action Types:在 Redux 中,所有的 action 类型需要事先定义,以便在创建 action 和 reducer 时引用//constants.js2.创建 Actions:使用定义好的 action types 创建 action 对象//actionCreators.js 3.编写 Reducers:根据 action 的类型更新 state//reducer.js4.引入并统一导出reducer 和 action//index.js	5.创建 Store:创建 Redux store,将 counter 和 home 的 reducer 进行合并成一个 reducer//store\index.js //参考:https://blog.csdn.net/kouzuhuai2956/article/details/145001802

redux-devtools 浏览器工具

给浏览器安装拓展:
在这里插入图片描述
按F12使用:可以看到存储在 redux 中的数据

在这里插入图片描述

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

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

相关文章

RK3588上编译opencv 及基于c++实现图像的读入

参考博文&#xff1a; https://blog.csdn.net/qq_47432746/article/details/147203889 一、安装依赖包 sudo apt install build-essential cmake git pkg-config libgtk-3-dev libavcodec-dev libavformat-dev libswscale-dev libv4l-dev libxvidcore-dev libx264-dev libjpe…

MATLAB 训练CNN模型 yolo v4

学生对小车控制提出了更好的要求&#xff0c;能否加入深度学习模型。 考虑到小车用matlab来做&#xff0c;yolo v5及以上版本都需要在pytorch下训练&#xff0c;还是用早期版本来演示。 1 yolov4 调用 参考 trainYOLOv4ObjectDetector (mathworks.com) name "tiny-yo…

Windows下使用 VS Code + g++ 开发 Qt GUI 项目的完整指南

&#x1f680; 使用 VS Code g 开发 Qt GUI 项目的完整指南&#xff08;Windows MSYS2&#xff09; 本指南帮助你在 Windows 下使用 VS Code g CMake Qt6 快速搭建 Qt GUI 项目&#xff0c;适合熟悉 Visual Studio 的开发者向跨平台 VS Code 工具链迁移。 &#x1f6e0;️…

开源漏洞扫描器:OpenVAS

一、OpenVAS介绍 OpenVAS (Open Vulnerability Assessment System) 是一款功能强大的开源漏洞扫描器。它由 Greenbone Networks 开发和维护&#xff0c;是 Greenbone 安全管理器 (GSM) 产品的基础&#xff0c;同时也有免费的社区版本&#xff08;Greenbone Community Edition&…

Redis Pipeline 详解

Redis Pipeline 详解 Redis 无 Pipeline 耗时情况 : #mermaid-svg-8RIiJyeBO0uIrWjr {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-8RIiJyeBO0uIrWjr .error-icon{fill:#552222;}#mermaid-svg-8RIiJyeBO0uIrWjr .…

2025.04.24【3D】3D绘图入门指南

Nifty graph A contribution by Matt Asher. 3D animation A 3D animated scatterplot made with R and rgl. 文章目录 Nifty graph3D animation 2025.04.24【3D】| 3D绘图入门指南什么是3D绘图&#xff1f;为什么使用3D绘图&#xff1f;如何在R中进行3D绘图&#xff1f;安装…

[特殊字符] 分布式事务中,@GlobalTransactional 与 @Transactional 到底怎么配合用?

在微服务架构中&#xff0c;随着系统模块的拆分&#xff0c;单体应用中的本地事务已经无法满足跨服务的数据一致性需求。此时&#xff0c;我们就需要引入分布式事务解决方案&#xff0c;比如 Seata。在使用 Seata 的过程中&#xff0c;很多人会遇到一个常见的疑问&#xff1a; …

TDengine 集群高可用方案设计(二)

四、TDengine 集群高可用方案设计 4.1 硬件与网络架构设计 服务器选型&#xff1a;选择配置高、稳定性强的服务器&#xff0c;如戴尔 PowerEdge R740xd、华为 RH2288H V5 等。以戴尔 PowerEdge R740xd 为例&#xff0c;它配备英特尔至强可扩展处理器&#xff0c;具备高性能计…

从对数变换到深度框架:逻辑回归与交叉熵的数学原理及PyTorch实战

目录 前言 一、连乘变连加二、最小化损失函数2.1交叉熵2.2 二分类交叉熵2.3 多分类交叉熵三、逻辑回归与二分类3.1 逻辑回归与二分类算法理论讲解3.1.1 散点输入3.1.2 前向计算3.1.3 Sigmoid函数引入3.1.4 参数初始化3.1.5 损失函数3.1.6 开始迭代3.1.7 梯度下降显示四、基于框…

高企复审奖补!2025年合肥市高新技术企业重新认定奖励补贴政策及申报条件

一、合肥市高新技术企业重新认定奖励补贴政策 &#xff08;一&#xff09;高新区高新技术企业重新认定复审补贴奖励 重新认定为国家高新技术企业的给予5万元一次性奖励。 &#xff08;二&#xff09;经开区高新技术企业重新认定复审补贴奖励 对重新认定的企业&#xff0c;给…

Spring Boot 中配置线程池时优化 `ThreadPoolTaskExecutor` 的配置总结

在 Spring Boot 中配置线程池时&#xff0c;可以通过以下方式进一步优化 ThreadPoolTaskExecutor 的配置&#xff0c;提升性能、灵活性和可靠性&#xff1a; 优化点 1&#xff1a;合理设置线程池参数 关键参数调整 Bean(name "taskExecutor") public Executor tas…

opencv 图像的旋转

图像的旋转 1 单点旋转2. 图片旋转&#xff08;cv2.getRotationMatrix2D&#xff09;3. 插值方法3.1 最近邻插值(cv2.INTER_NEAREST)3.2 双线性插值(cv2.INTER_LINEAR)3.3 像素区域插值&#xff08;cv2.INTER_AREA&#xff09;3.4 双三次插值&#xff08;cv2.INTER_CUBIC&#…

如何在 Odoo 18 中配置自动化动作

如何在 Odoo 18 中配置自动化动作 Odoo是一款多功能的业务管理平台&#xff0c;旨在帮助各种规模的企业更高效地处理日常运营。凭借其涵盖销售、库存、客户关系管理&#xff08;CRM&#xff09;、会计和人力资源等领域的多样化模块&#xff0c;Odoo 简化了业务流程&#xff0c…

每日两道leetcode

345. 反转字符串中的元音字母 - 力扣&#xff08;LeetCode&#xff09; 题目 给你一个字符串 s &#xff0c;仅反转字符串中的所有元音字母&#xff0c;并返回结果字符串。 元音字母包括 a、e、i、o、u&#xff0c;且可能以大小写两种形式出现不止一次。 示例 1&#xff1a;…

【SQL 基础入门 1. -- SQL 基本语法详解及举例】

文章目录 SQL 数据库创建及使用删除数据库SQL 查看数据空中有哪些表格SQL 创建表格SQL 修改表格列数据格式SQL 表格插入数据SQL 查看表格类型组成SQL 查看表格中的内容 SQL 查询语句SQL 查看指定列SQL 选择指定列SQL 按指定列进行升序排序SQL 平均值/求和/最大值/最小值 SQL 数…

PostgreSQL 分区表——范围分区SQL实践

PostgreSQL 分区表——范围分区SQL实践 1、环境准备1-1、新增原始表1-2、执行脚本新增2400w行1-3、创建pg分区表-分区键为创建时间1-4、创建24年所有分区1-5、设置默认分区&#xff08;兜底用&#xff09;1-6、迁移数据1-7、创建分区表索引 2、SQL增删改查测试2-1、查询速度对比…

Apache Flink 深度解析:流处理引擎的核心原理与生产实践指南

Apache Flink 深度解析&#xff1a;流处理引擎的核心原理与生产实践指南 引言&#xff1a;实时计算的范式革命 2023年双十一期间&#xff0c;某头部电商平台基于Flink构建的实时风控系统成功拦截了每秒超过120万次的异常交易请求。这背后是Apache Flink作为第四代计算引擎的强…

【Java学习笔记】选择结构

选择结构 内容结构 一、顺序结构 二、分支控制 &#xff08;1&#xff09;单分支 &#xff08;2&#xff09;双分支 &#xff08;3&#xff09;多分支 &#xff08;4&#xff09;嵌套分支 &#xff08;5&#xff09;switch 分支结构 三、switch和if的比较 一、顺序结构…

03_JavaScript

文章目录 一、概述1.1、JavaScript简介1.2、JavaScript组成部分1.3、为什么要学习JavaScript1.4、学习的目的1.5、JavaScript与Java的关系 二、使用位置及运行说明2.1、使用位置2.2、如何运行 三、JavaScript基础语法3.1、变量3.2、运算符3.3、控制流程3.3.1、分支结构3.3.2、循…

PySide6 GUI 学习笔记——常用类及控件使用方法(常用类矩阵QRect)

文章目录 一、构造与初始化方法二、坐标与尺寸获取三、坐标与尺寸设置四、几何运算方法五、移动与调整方法六、状态判断方法七、类型转换方法八、操作符重载九、静态方法十、特殊方法附录方法速查表注意的问题交集和并集图解 &#x1f4d8; PySide6.QtCore.QRect 使用整数精度定…