当前位置: 首页 > news >正文

react js自定义实现状态管理

redux基础实现

myRedux

export const createStore = (reduce) => {if (typeof reduce !== 'function') throw new Error('Expected the reducer to be a function.')let state,listeners = []state = reduce()const getState = () => stateconst dispatch = (action) => {if(typeof action !== 'object' || typeof action.type !== 'string') throw new Error('Actions must be plain objects.')state = reduce(state, action)listeners.forEach(listener => listener())}const subscribe = (listener) => {if(typeof listener !== 'function') throw new Error('Expected the listener to be a function.')listeners.push(listener)return () => listeners = listeners.filter(l => l !== listener)}return {getState,dispatch,subscribe,}
}

使用

import React, { useEffect, useState } from 'react'
import { createStore } from './myRedux'const reduce = (state = { a: 123 }, action = {}) => {state = { ...state }switch (action.type) {case 'tset':state.a = Math.random() * 1000return statedefault:return state}}
const store = createStore(reduce)export default function Test() {const state = store.getState()const [_, foceUpdate] = useState(0)useEffect(() => {store.subscribe(() => {foceUpdate(Date.now())})}, [])const change = () => {store.dispatch({ type: 'tset' })}return (<div><h1>Test {state.a}</h1><button onClick={change} >change</button></div>)
}

react-redux

和源码可能不同,我没看过源码,只是实现一下

react-redux.js

import { useContext, useEffect, useState, createContext } from 'react'
const StoreContext = createContext()
export const Provider = (props) => {const store = props.storereturn <StoreContext.Provider value={{ store }}>{props.children}</StoreContext.Provider>
}export const connect = (mapState, mapDispatch) => {if (typeof mapState !== 'function') throw new Error('mapState must be an function')if (typeof mapDispatch !== 'function') throw new Error('mapDispatch must be an function')return (Cpn) => {return (props = {}) => {const contents = useContext(StoreContext)const store = contents.storeconst state = mapState(store.getState())const dispatch = mapDispatch(store.dispatch)const [_, forceUpdate] = useState(true)useEffect(() => {store.subscribe(() => {forceUpdate(Symbol())})}, [])props = { ...props, ...state, ...dispatch }return <Cpn {...props} />}}
}

使用

import React from 'react'
import { Provider, connect } from './react-redux'
import { createStore } from 'redux'
const reducer = (state = { name: 'test' }, action) => {switch (action.type) {case 'CHANGE_NAME':return { ...state, name: action.name }default:return state}
}
const store = createStore(reducer)function Test2(props) {const change = () => {props.changeName('test' + Math.random())}return (<div><h1>Test {props.name} </h1><button onClick={change} >change</button></div>)
}
const Test3 = connect(state => ({ name: state.name }),dispatch => ({ changeName: (name) => dispatch({ type: "CHANGE_NAME", name }) })
)(Test2)export default function Test() {return (<Provider store={store} ><Test3 /></Provider>)
}

模仿pinia方式管理

myPinia.js

import { useEffect, useState } from 'react'class StoreState {constructor(value) {this.value = valuethis.symbol = Symbol()}
}export const createStore = (f) => {if (typeof f !== 'function') throw new Error('Expected a function')const store = f()watch(store)const useStore = () => {return new Proxy(store, {get: (target, prop) => {const v = target[prop]const isState = v instanceof StoreStatereturn isState ? v.value : v},set: () => store,})}return useStore
}export const useStoreState = (v) => {return new StoreState(v)
}const watch = (obj) => {Object.keys(obj).forEach((key) => {const storeState = obj[key]if (storeState instanceof StoreState) {let value = storeState.valueObject.defineProperty(storeState, 'value', {get: () => value,set: (newValue) => {value = newValueupdateView()},})}})
}let listeners = []
export const subscribe = (f) => {if (typeof f !== 'function') throw new Error('Expected a function')if (!listeners.includes(f)) listeners.push(f)return () => (listeners = listeners.filter((l) => l !== f))
}
const updateView = () => listeners.forEach((f) => f())export const connect = (Cpn) => {return (props) => {const [_, forceUpdate] = useState(true)useEffect(() => {const unSubscribe = subscribe(() => forceUpdate(Symbol()))return unSubscribe}, [])return <Cpn {...props} />}
}

使用

import React from 'react'
import { createStore, useStoreState, connect } from './myPinia'const useUserStore = createStore(() => {let name = useStoreState('test')const change = () => {name.value = 'test2' + Math.random()}return { name, change }
})function Test() {const store = useUserStore()const change = () => {store.change()}return (<div><h2>Test {store.name}</h2><button onClick={change}>change</button></div>)
}export default connect(Test)

不足的是,还是需要forceUpdate

react-pinia

实现模块化

react-pinia.js

import { useEffect, useState } from 'react'
const storePool = {}
export const createStore = (id, f) => {if (typeof f !== 'function') throw new Error('Expected a function')const store = f()watchStore(store)const proxy = new Proxy(store, {get: (target, prop) => {const v = target[prop]const isState = v instanceof StoreStatereturn isState ? v.value : v},set: () => store,})storePool[id] = { store }const useStore = () => proxyreturn useStore
}class StoreState {constructor(value) {this.value = valuethis.symbol = Symbol()}
}
export const useStoreState = (v) => {return new StoreState(v)
}const watchStore = (obj) => {Object.keys(obj).forEach((key) => {const storeState = obj[key]if (storeState instanceof StoreState) {let value = storeState.valueconst symbol = storeState.symbolObject.defineProperty(storeState, 'value', {get: () => {return value},set: (newValue) => {value = newValueupdateView(symbol)},})}})
}let listenersPool = {}
export const subscribe = (symbol, f) => {if (typeof symbol !== 'symbol') throw new Error('Expected a symbol')if (typeof f !== 'function') throw new Error('Expected a function')const listeners = listenersPool[symbol] || []if (!listeners.includes(f)) listeners.push(f)listenersPool[symbol] = listenersreturn () => (listenersPool[symbol] = listenersPool[symbol].filter((l) => l !== f))
}
const updateView = (symbol) => {if (typeof symbol !== 'symbol') returnconst listeners = listenersPool[symbol] || []listeners.forEach((f) => f())
}export const connect = (map) => {const symbolArr = []const stores = (() => {const obj = {}Object.keys(storePool).forEach((key) => {const store = storePool[key].storeconst proxy = new Proxy(store, {get: (target, prop) => {const v = target[prop]const isState = v instanceof StoreStateif (isState) {const symbol = v.symbolif (!symbolArr.includes(symbol)) symbolArr.push(symbol)return v.value}return v},set: () => store,})obj[key] = proxy})return obj})()const mapStore = map(stores) || {}const mapStoreToProps = Object.prototype.toString.call(mapStore) === '[object Object]' ? mapStore : {}return (Cpn) => {return (props) => {const [, forceUpdate] = useState(true)useEffect(() => {const unSubscribe = symbolArr.map((id) => subscribe(id, () => forceUpdate(Symbol())))return () => unSubscribe.forEach((f) => f())}, [])return <Cpn {...props} {...mapStoreToProps} />}}
}

使用

import React, { useState } from 'react'
import { createStore, useStoreState, connect } from './react-pinia'// user store
const useUserStore = createStore('user', () => {let name = useStoreState('userStore')const change = () => {name.value = 'userStore' + Math.random()}return { name, change }
})
// test store
const useTestStore = createStore('test', () => {const test = useStoreState('testStore')const changeTest = () => {test.value = 'testStore' + Math.random()}return { test, changeTest }
}
)
const Test1 = () => {console.log('render Test1');const [showTest2, setShowTest2] = useState(true)return (<div><h1>test1</h1><button onClick={() => setShowTest2(false)} >hideTest2</button>{showTest2 && <Test2 />}<Test3 /></div>)
}const Test2 = connect(store => ({ name: store.user.name }))((props) => {console.log('render Test2', props);const store = useUserStore()const change = () => {store.change()}return (<div><h2>Test2 {store.name}</h2><button onClick={change}>change</button></div>)
}
)const Test3 = connect(store => [store.test.test])(() => {console.log('render Test3');const store = useTestStore()const change = () => {store.changeTest()}return (<div><h2>Test3 {store.test}</h2><button onClick={change}>change</button></div>)
}
)
export default Test1

相关文章:

react js自定义实现状态管理

redux基础实现 myRedux export const createStore (reduce) > {if (typeof reduce ! function) throw new Error(Expected the reducer to be a function.)let state,listeners []state reduce()const getState () > stateconst dispatch (action) > {if(typeo…...

行为型设计模式——中介者模式

中介者模式 中介者模式主要是将关联关系由一个中介者类统一管理维护&#xff0c;一般来说&#xff0c;同事类之间的关系是比较复杂的&#xff0c;多个同事类之间互相关联时&#xff0c;他们之间的关系会呈现为复杂的网状结构&#xff0c;这是一种过度耦合的架构&#xff0c;即…...

通信行业无线基本概念

fast roaming&#xff08;快速漫游&#xff09;&#xff1a;使用户在不同的基站&#xff08;access point&#xff09;间可以平滑的切换&#xff0c;在802.11r协议标准中定义。band steering&#xff08;波段转向&#xff09;&#xff1a;在双频段&#xff08;2.4G和5G&#xf…...

grep 在运维中的常用可选项

一、对比两个文件 vim -d <filename1> <filename2> 演示&#xff1a; 需求&#xff1a;&#xff5e;目录下有两个文件一个test.txt 以及 text2.txt,需求对比两个文件的内容。 执行后会显示如图&#xff0c;不同会高亮。 二、两次过滤 场景&#xff1a;当需要多…...

python读取Dicom文件

文章目录 1. pydicom Library2. SimpleITK Library3. ITK Library (Insight Toolkit)4. GDCM Library (Grassroots DICOM) 下面提供几种用python方法读取Dicom文件 1. pydicom Library import pydicom # Read DICOM file dataset pydicom.dcmread("path_to_dicom_file.d…...

UL2034详细介绍UL 安全单站和多站一氧化碳报警器标准

在介绍相关标准之前先介绍一下UL认证和UL测试报告的区别&#xff0c;检测认证行业6年老司机 UL认证是自愿性的认证&#xff0c;需要检测产品和审核工厂&#xff0c;每个季度审核一次&#xff0c;费用高、时间久&#xff0c;而且审厂非常的严格。 UL测试报告是根据产品选用相应…...

鸿蒙HarmonyOS-SDK管理使用指南

鸿蒙HarmonyOS-SDK管理使用指南 文章目录 鸿蒙HarmonyOS-SDK管理使用指南sdkmgr使用指导查看SDK组件安装组件卸载组件查看sdkmgr版本查看sdkmgr帮助options选项说明ohsdkmgr使用指导查看SDK组件安装组件卸载组件查看ohsdkmgr版本查看ohsdkmgr帮助option...

QT上位机开发(进度条操作)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 进度条是一个比较常见的控件。如果某个操作需要很长的时间才能完成&#xff0c;那么这个时候最好有一个进度条提示&#xff0c;这样比较容易平复一…...

637_二叉树的层平均值

描述 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受 思路 无需思路&#xff0c;乱杀 解答 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, righ…...

Ubuntu20.4 Mono C# gtk 编程习练笔记(三)

Mono对gtk做了很努力的封装&#xff0c;即便如此仍然与System.Windows.Form中的控件操作方法有许多差异&#xff0c;这是gtk本身特性或称为特色决定的。下面是gtk常用控件在Mono C#中的一些用法。 Button控件 在工具箱中该控件的clicked信号双击后自动生成回调函数prototype&…...

What is `JsonSanitizer.sanitize` does?

JsonSanitizer.sanitize 是一个Java库中的方法&#xff0c;用于处理和净化JSON字符串&#xff0c;特别是针对跨站脚本攻击&#xff08;XSS, Cross-Site Scripting&#xff09;。 例如&#xff0c;在处理富文本内容、用户评论、从第三方服务获取的数据时&#xff0c;使用 JsonSa…...

K8S测试pod

背景 用于测试ping&#xff0c;curl等类型的pod Centos pod apiVersion: apps/v1 kind: Deployment metadata:name: centos-deploymentlabels:app: centos spec:replicas: 1selector:matchLabels:app: centostemplate:metadata:labels:app: centosspec:containers:- name: c…...

序章 熟悉战场篇—了解vue的基本操作

了解vue 的基本目录&#xff1a; dist 是打包后存放的目录(打包目录后续可以改)node_modules 是依赖包public 是静态index页面src 是存放文件的目录assets 是存放静态资源的目录components 是存放组件的目录views 是存放页面文件的目录&#xff08;没有views 自己新建一个&…...

MongoDB聚合:$bucketAuto

按照指定的表达式对输入文档进行分类后放入指定数字的桶中&#xff0c;跟$bucket不太一样&#xff0c;$bucketAuto可以指定分组的数量&#xff08;颗粒度&#xff09;&#xff0c;$bucketAuto会根据groupBy的值和颗粒度自动生成桶的边界。 语法 {$bucketAuto: {groupBy: <…...

认识监控系统zabbix

利用一个优秀的监控软件&#xff0c;我们可以: ●通过一个友好的界面进行浏览整个网站所有的服务器状态 ●可以在 Web 前端方便的查看监控数据 ●可以回溯寻找事故发生时系统的问题和报警情况 了解zabbix zabbix是什么&#xff1f; ●zabbix 是一个基于 Web 界面的提供分布…...

东北编程语言???

在GitHub闲逛&#xff0c;偶然发现了东北编程语言&#xff1a; 东北编程语言是由Zhanyong Wan创造的&#xff0c;它使用东北方言词汇作为基本关键字。这种编程语言的特点是简单易懂&#xff0c;适合小学文化程度的人学习&#xff0c;并且易于阅读、编写和记忆。它的语法与其他编…...

React16源码: React中的schedule调度整体流程

schedule调度的整体流程 React Fiber Scheduler 是 react16 最核心的一部分&#xff0c;这块在 react-reconciler 这个包中这个包的核心是 fiber reconciler&#xff0c;也即是 fiber 结构fiber 的结构帮助我们把react整个树的应用&#xff0c;更新的流程&#xff0c;能够拆成…...

springboot mybatis-plus swing实现报警监听

通过声音控制报警器&#xff0c;实现声光报警&#xff0c;使用beautyeye_lnf.jar美化界面如下 EnableTransactionManagement(proxyTargetClass true) SpringBootApplication EnableScheduling public class AlarmWarnApplication {public static void main(String[] args) …...

【计算机网络】网络层——详解IP协议

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】 本专栏旨在分享学习计算机网络的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 &#x1f431;一、I…...

【Java数据结构】03-二叉树,树和森林

4 二叉树、树和森林 重点章节&#xff0c;在选择&#xff0c;填空&#xff0c;综合中都有考察到。 4.1 掌握二叉树、树和森林的定义以及它们之间的异同点 1. 二叉树&#xff08;Binary Tree&#xff09; 定义&#xff1a; 二叉树是一种特殊的树结构&#xff0c;其中每个节点…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

comfyui 工作流中 图生视频 如何增加视频的长度到5秒

comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗&#xff1f; 在ComfyUI中实现图生视频并延长到5秒&#xff0c;需要结合多个扩展和技巧。以下是完整解决方案&#xff1a; 核心工作流配置&#xff08;24fps下5秒120帧&#xff09; #mermaid-svg-yP…...

二维FDTD算法仿真

二维FDTD算法仿真&#xff0c;并带完全匹配层&#xff0c;输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...

CppCon 2015 学习:Time Programming Fundamentals

Civil Time 公历时间 特点&#xff1a; 共 6 个字段&#xff1a; Year&#xff08;年&#xff09;Month&#xff08;月&#xff09;Day&#xff08;日&#xff09;Hour&#xff08;小时&#xff09;Minute&#xff08;分钟&#xff09;Second&#xff08;秒&#xff09; 表示…...