react状态管理

状态管理的实现

  1. 组件之外,可以在全局共享状态/数据

    1. closure(闭包) 可以解决
  2. 有修改这个数据的明确方法,并且,能够让其他的方法感知到。

    1. 本质上,就是把监听函数放在一个地方,必要时拿出来执行一下。
      1. 发布订阅
      2. new Proxy / Object.defineProperty
  3. 修改状态, 会触发 UI 更新

    1. forceUpdate
    2. setState
    3. useState

手写实现一个redux

index.jsx

import React, { useEffect, useState } from 'react';
import { createData } from './data';
const initState = {count : 1,age: 18,
}
const myReducer = (data,action)=>{switch(action.type){case "INCREMENT":return { ...data, count: data.count + 1 };case "DECREMENT":return { ...data, count: data.count - 1 };case "GROW_UP":return { ...data, age: data.age + 1 };default:return data;}
}
const dataObj  = createData(initState ,myReducer)
export default function GetData(){const [count, setCount] = useState(1)useEffect(() => {dataObject.subscribe(() => {let currentData = dataObject.getData();console.log('the subscribed data is: ', currentData);setCount(currentData.count);})}, [])const addClick = ()=>{createData.setDataByAction({type : "INCREMENT"})}const deleteClick= ()=>{createData.setDataByAction({type : "DECREMENT"})}return (<div><button onClick={addClick}>+</button><button onClick={deleteClick}>-</button></div>)
}

data.js

export const createData = function(init, reducer) {let data = init;let deps = [];function getData() {return data;};function subscribe(handler) {// 我们希望,订阅了这个数据的 handler,在数据改变时,都能执行。deps.push(handler);}function UNSAFE_changeData(newData) {// 我们提供一个,修改这个 data 的方法data = newData;deps.forEach(fn => fn())}function setDataByAction(action) {data = reducer(data, action);deps.forEach(fn => fn())}// 既然 UNSAFE_changeData, 我们是不是要提供一个可预测的,可以固定能力去修改 data 的逻辑。// action, action 代表,我要如何修改这个数据。return {getData, subscribe, UNSAFE_changeData, setDataByAction}
};

手写reducer合并

模拟定义redux的createStore 和 combineReducer 方法(redux.js)

export const createStore = function(reducer, initState) {let state = initState;let listeners = [];function getState() {return state;};function subscribe(handler) {// 我们希望,订阅了这个数据的 handler,在数据改变时,都能执行。listeners.push(handler);};function dispatch(action) {// dispatch 一个 action, 通过你们注册的 reducer,生成一个新的 state, 最后作用在界面上。// immutable, 我没有改变 state 本身,而是生成了一个新的 state const currentState = reducer(state, action);state = currentState;listeners.forEach(fn => fn())};dispatch({ type: Symbol()});// 既然 UNSAFE_changeData, 我们是不是要提供一个可预测的,可以固定能力去修改 data 的逻辑。// action, action 代表,我要如何修改这个数据。return {getState, subscribe, dispatch}
};export const combineReducer = function(reducers) {const keys = Object.keys(reducers); // 先拿到[counter, info];return function(state = {}, action) {const nextState = {};keys.forEach((key) => {const reducer = reducers[key]; // counterRuducer, infoReducerconst prev = state[key]; // counter: {count: 0}, info: {age: 18}// 假设我是 ADD_COUNT 的 action, 那么循环执行完了以后,nextState 是不是分别为:// counter: {count: 1}, info: {age: 18}const next = reducer(prev, action); nextState[key] = next;});return nextState;}
}

调用:
配置storejs文件

import { combineReducer, createStore } from "./redux";
let initState = {counter: {count: 0},info: {name: 'xxx'}
}
function counterReducer(state, action){switch(action.type){//xxx省略代码}
}
function infoReducer(state, action){switch(action.type){//xxx省略代码}
}
const reducers = combineReducer({counter:counterReducer,info:infoReducer
})
const store = createStore(reducers,initState)
export default store

connect实现传参

定义一个上下文context.js

import { createContext } from "react";
const _context = createContext({});
export default _context;

调用

import ReactContext from './context'
import store from './store'
<ReactContext.Provider value={store}><App/>
</ReactContext.Provider>

通过Provider ,可以使用Consumer 调用传递的store数据,并且通过connect可以直接调用store的方法和数据。connect原理其实通过配置高阶组件,返回一个新的组件,将store和组件结合起来

connect两个参数:mapStateToProps, mapDispatchToProps

import { useContext, useEffect, useState } from "react"
import ReduxContext from './context';export const connect = (mapStateToProps, mapDispatchToProps) => Component => {return function ConnectComponent(props) {const _store = useContext(ReduxContext);const [, setBool] = useState(true);const forceUpdate = () => setBool(val => !val);useEffect(() => {_store.subscribe(forceUpdate);}, [])return (<ReduxContext.Consumer>{store => <Component {...props}{...mapStateToProps(store.getState())}{...mapDispatchToProps(store.dispatch)}/>}</ReduxContext.Consumer>)}
}

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

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

相关文章

Java数据结构与算法(最小栈)

前言 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void pop() 删除堆栈顶部的元素。int top() 获取堆栈顶部的元素。i…

Educational Codeforces Round 160 C. Game with Multiset (贪心之尽量选最大来填满)

在这个问题中&#xff0c;最初会给你一个空的多集。您必须处理两种类型的查询&#xff1a; ADD x x x - 在多集合中添加一个等于 2 x 2x 2x 的元素&#xff1b; GET w w w - 询问是否可以求当前多集的某个子集的和&#xff0c;并得到等于 w w w 的值。 输入 第一行包含一…

java后端轮播图的设计

对于表示轮播图位置这种有限且较小范围的数据&#xff0c;一般可以使用整数类型来表示。考虑到位置序号一般是非负整数且数量较少&#xff0c;可以选择使用小范围的整数类型&#xff0c;如下&#xff1a; 整数类型: 对于Java中&#xff0c;可以考虑使用 int 类型来表示位置序号…

Vue3 ts实现将assets中的图片转为file格式,实现本地图片选择上传功能

Vue3 ts实现将assets中的图片转为file格式&#xff0c;实现本地图片选择上传功能 1、需求描述2、关键代码3、img标签src使用变量打包后图片无法展示 1、需求描述 用户可以选项系统固定的几个图标&#xff0c;也可以自定义上传图片。系统固定图标存在 src\assets\images\app 路径…

sql注入——时间盲注

在sql注入的第九关中&#xff0c;我们既看不到返回值&#xff0c;也不能通过布尔盲注得到结果&#xff0c;这个时候还有一种方法就是通过页面反应时间来获取信息&#xff0c;就是时间盲注 第九关的代码&#xff0c;可以看到无论是否正确&#xff0c;页面都会返回You are in 可…

4---git命令详解第一部分

一、提交文件方面命令&#xff1a; 1.1第一步&#xff1a;将需要提交的文件放进暂存区&#xff1a; 添加单个文件到暂存区stage&#xff1a; git add 文件名 添加多个文件到暂存区&#xff1a; git add 文件名1 文件名2 ... 将目录下所有文件添加到暂存区&#xff1a; git…

【漏洞复现】用友U8 CRM uploadfile 文件上传致RCE漏洞

0x01 产品简介 用友U8 Cloud是用友推出的新一代云ERP&#xff0c;主要聚焦成长型、创新型企业&#xff0c;提供企业级云ERP整体解决方案。 0x02 漏洞概述 用友 U8 CRM客户关系管理系统 uploadfle.php 文件存在任意文件上传漏洞&#xff0c;未经身份验证的攻击者通过漏洞上传…

Java基础入门day52

day52 servlet 综合案例 登录功能 设置欢迎页 <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&q…

SpringBoot 国际化

如下四步 1 建资源文件 2 在yml文件中指定资源文件名称 3 自定义类型转换&#xff0c;转换locale Configuration public class DefaultLocaleResolver implements LocaleResolver {Overridepublic Locale resolveLocale(HttpServletRequest request) {String locrequest.getP…

基于语音识别的智能电子病历(三)之 M*Modal

讨论“基于语音识别的智能电子病历”&#xff0c;就绕不开 Nuance 和 M*Modal。这2个公司长时间的占据第一和第二的位置。下面介绍一下M*Modal。 这是2019年的一个新闻“专业医疗软件提供商3M公司为自己购买了一份圣诞礼物&#xff0c;即M*Modal IP LLC的医疗技术业务&#xf…

SQL靶场搭建

概述 简单介绍一下SQL靶场的搭建&#xff0c;以及在搭建过程中遇到的一些问题。使用该软件搭建靶场相对简单&#xff0c;适合新手小白。当然&#xff0c;也可以在自己的虚拟机下进行搭建&#xff0c;相对来说就较为复杂。本章主要讲解使用Phpstudy进行SQL靶场搭建。 这里我推…

前后端编程语言和运行环境的理解

我已重新检查了我的回答,并确保信息的准确性。以下是常用的编程语言,以及它们通常用于前端或后端开发,以及相应的框架和运行环境: 前端开发 JavaScript 框架:React, Angular, Vue.js, Ember.js, Backbone.js运行环境:Web 浏览器HTML (HyperText Markup Language) 不是编…

嵌入式学习——3——TCP-UDP 数据交互,握手,挥手

1、更新源 cd /etc/apt/ sudo cp sources.list sources.list.save 将原镜像备份 sudo vim sources.list 将原镜像修改成阿里源/清华源&#xff0c;如所述 阿里源 deb http://mirrors.aliyun.com/ubuntu/ bionic main …

Flutter 中的 DrawerController 小部件:全面指南

Flutter 中的 DrawerController 小部件&#xff1a;全面指南 Flutter 是一个流行的跨平台移动应用开发框架&#xff0c;它提供了丰富的组件和工具来帮助开发者构建高质量的应用。在Flutter中&#xff0c;DrawerController并不是一个内置的组件&#xff0c;但是它的概念可以用于…

每周题解:牛的旅行

题目描述 牛的旅行 农民John的农场里有很多牧区。有的路径连接一些特定的牧区。一片所有连通的牧区称为一个牧场。但是就目前而言&#xff0c;你能看到至少有两个牧区不连通。 现在&#xff0c;John想在农场里添加一条路径 ( 注意&#xff0c;恰好一条 )。对这条路径有这样的…

RA-RISK ANALYSIS

文章目录 一、期刊简介二、征稿信息三、期刊表现四、投稿须知五、咨询 一、期刊简介 Risk Analysis代表风险分析学会出版&#xff0c;在ISI期刊引文报告中的社会科学、数学方法类别中排名前10位&#xff0c;为风险分析领域的新发展提供了焦点。这本国际同行评审期刊致力于发表…

MultiHop-RAG:多跳查询的基准检索增强生成

【摘要】检索增强生成&#xff08;RAG&#xff09;通过检索相关知识来增强大语言模型&#xff08;LLM&#xff09;&#xff0c;在减轻 LLM 幻觉和提高响应质量方面显示出巨大的潜力&#xff0c;从而促进 LLM 在实践中的广泛采用。然而&#xff0c;我们发现现有的 RAG 系统不足以…

DNS域名解析服务器搭建

基础介绍 DNS 从哪里获取 IP 地址&#xff1f; 本地缓存&#xff1a; DNS服务器会将先前查询过的域名和对应的IP地址存储在本地缓存中&#xff0c;以便在后续查询中加快响应速度。如果之前已经查询过某个域名&#xff0c;DNS服务器会直接从本地缓存中获取对应的IP地址。递归查…

02. Redis 事务

文章目录 Redis 事务执行事务放弃事务编译性异常运行时异常 Redis 事务 Redis 单条明令是原子性的&#xff0c;但Redis事务不保证原子性。 事务的本质就是&#xff1a;一组命令一起执行&#xff01;一个事务中的所有命令都会被序列化&#xff0c;在事务执行过程中&#xff0c;会…

2024-05-19 问AI: 大语言模型的BPE方向是什么意思?

文心一言 大语言模型的上下文中&#xff0c;BPE&#xff08;Byte-Pair Encoding&#xff09;是一种常用的子词单元&#xff08;subword unit&#xff09;编码方法&#xff0c;尤其在处理自然语言处理任务时。这种方法的主要目的是解决自然语言中的词汇表大小问题&#xff0c;特…