react全局状态管理_rxv: 在React中用Vue3的reactivity包实现状态管理。

前言

React的状态管理是一个缤纷繁杂的大世界,光我知道的就不下数十种,其中有最出名immutable阵营的redux,有mutable阵营的mobxreact-easy-state,在hooks诞生后还有极简主义的unstated-next,有蚂蚁金服的大佬出品的hoxhoox

其实社区诞生这么多种状态管理框架,也说明状态管理库之间都有一些让人不满足的地方。

rxv是我依据这些痛点,并且直接引入了Vue3的package: @vue/reactivity去做的一个React状态管理框架,下面先看一个简单的示例:

示例

// store.ts
import { reactive, computed, effect } from '@vue/reactivity';export const state = reactive({count: 0,
});const plusOne = computed(() => state.count + 1);effect(() => {console.log('plusOne changed: ', plusOne);
});const add = () => (state.count += 1);export const mutations = {// mutationadd,
};export const store = {state,computed: {plusOne,},
};export type Store = typeof store;
// Index.tsx
import { Provider, useStore } from 'rxv'
import { mutations, store, Store } from './store.ts'
function Count() {const countState = useStore((store: Store) => {const { state, computed } = store;const { count } = state;const { plusOne } = computed;return {count,plusOne,};});return (<Card hoverable style={{ marginBottom: 24 }}><h1>计数器</h1><div className="chunk"><div className="chunk">store中的count现在是 {countState.count}</div><div className="chunk">computed值中的plusOne现在是 {countState.plusOne.value}</div><Button onClick={mutations.add}>add</Button></div></Card>);
}export default () => {return (<Provider value={store}><Count /></Provider>);
};

可以看出,store的定义只用到了@vue/reactivity,而rxv只是在组件中做了一层桥接,连通了Vue3和React,正如它名字的含义:React x Vue。

一些痛点

根据我自己的看法,我先简单的总结一下现有的状态管理库中或多或少存在的一些不足之处:

  1. redux为代表的,语法比较冗余,样板文件比较多。
  2. mobx很好,但是也需要单独的学一套api,对于react组件的侵入性较强,装饰器语法不稳定。
  3. unstated-next是一个极简的框架,对于React Hook做了一层较浅的封装。
  4. react-easy-state引入了observe-util,这个库对于响应式的处理很接近Vue3,我想要的了。

下面展开来讲:

options-based的痛点

Vuex和dva的options-based的模式现在看来弊端多多。具体的可以看尤大在vue-composition-api文档中总结的。

简单来说就是一个组件有好几个功能点,但是这几个功能点在分散在data,methods,computed中,形成了一个杂乱无章的结构。

当你想维护一个功能,你不得不先完整的看完这个配置对象的全貌。

心惊胆战的去掉几行,改掉几行,说不定会遗留一些没用的代码,也或者隐藏在computed选项里的某个相关的函数悄悄的坑了你...

而hook带来的好处是更加灵活的代码组织方式。

redux

直接引入dan自己的吐槽吧,要学的概念太多,写一个简单的功能要在五个文件之间跳来跳去,好头疼。redux的弊端在社区被讨论也不是一天两天了,相信写过redux的你也是深有同感。

ace7f47d920b5e799102ce13b85244b3.png

unstated-next

unstated-next其实很不错了,源码就40来行。最大程度的利用了React Hook的能力,写一个model就是写一个自定义hook。但是极简也带来了一些问题:

  1. 模块之间没有相互访问的能力。
  2. Context的性能问题,让你需要关注模块的划分。(具体可以看我这篇文章的性能章节
  3. 模块划分的问题,如果全放在一个Provider,那么更新的粒度太大,所有用了useContext的组件都会重复渲染。如果放在多个Provider里,那么就会回到第一条痛点,这些模块之间是相互独立的,没法互相访问。
  4. hook带来的一些心智负担的问题。React Hooks 你真的用对了吗?

react-easy-state

这个库引入的observe-util其实和Vue3 reactivity部分的核心实现很相似,关于原理解析也可以看我之前写的两篇文章:带你彻底搞懂Vue3的Proxy响应式原理!TypeScript从零实现基于Proxy的响应式库。带你彻底搞懂Vue3的Proxy响应式原理!基于函数劫持实现Map和Set的响应式。

  1. 似乎不维护了。
  2. 对于异步队列的处理过于hack,带来了很多issue,而且一直没有解决。

那其实转而一想,Vue3 reactivity其实是observe-util的强化版,它拥有了更多的定制能力,如果我们能把这部分直接接入到状态管理库中,岂不是完全拥有了Vue3的响应式能力。

原理分析

vue-next是Vue3的源码仓库,Vue3采用lerna做package的划分,而响应式能力@vue/reactivity被划分到了单独的一个package中

从这个包提供的几个核心api来分析:

effect

effect其实是响应式库中一个通用的概念:观察函数,就像Vue2中的Watcher,mobx中的autorunobserver一样,它的作用是收集依赖

它接受的是一个函数,这个函数内部对于响应式数据的访问都可以收集依赖,那么在响应式数据更新后,就会触发响应的更新事件。

reactive

响应式数据的核心api,这个api返回的是一个proxy,对上面所有属性的访问都会被劫持,从而在get的时候收集依赖(也就是正在运行的effect),在set的时候触发更新。

ref

对于简单数据类型比如number,我们不可能像这样去做:

let data = reactive(2)
//  oops
data = 5

这是不符合响应式的拦截规则的,没有办法能拦截到data本身的改变,只能拦截到data身上的属性的改变,所以有了ref。

const data = ref(2)
//  ok
data.value= 5

computed

计算属性,依赖值更新以后,它的值也会随之自动更新。其实computed内部也是一个effect。

拥有在computed中观察另一个computed数据、effect观察computed改变之类的高级特性。

实现

从这几个核心api来看,只要effect能接入到React系统中,那么其他的api都没什么问题,因为它们只是去收集effect的毅力,去通知effect触发更新。

effect接受的是一个函数,而且effect还支持通过传入schedule参数来自定义依赖更新的时候需要触发什么函数,

rxv的核心api: useStore接受的也是一个函数selector,它会让用户自己选择在组件中需要访问的数据。

那么思路就显而易见了:

  1. selector包装在effect中执行,去收集依赖。
  2. 指定依赖发生更新时,需要调用的函数是当前正在使用useStore的这个组件的forceUpdate强制渲染函数。

这样不就实现了数据变化,组件自动更新吗?

简单的看一下核心实现

export const useStore = <T, S>(selector: Selector<T, S>): S => {const forceUpdate = useForceUpdate();const store = useStoreContext();const effection = useEffection(() => selector(store), {scheduler: forceUpdate,lazy: true,});const value = effection();return value;
};
  1. 先通过useForceUpdate在当前组件中注册一个强制更新的函数。
  2. 通过useContext读取用户从Provider中传入的store。
  3. 再通过Vue的effect去帮我们执行selector(store),并且指定scheduler为forceUpdate,这样就完成了依赖收集。

就简单的几行代码,就实现了在React中使用@vue/reactivity中的所有能力。

优点:

  1. 直接引入@vue/reacivity,完全使用Vue3的reactivity能力,拥有computed, effect等各种能力,并且对于Set和Map也提供了响应式的能力。后续也会随着这个库的更新变得更加完善的和强大。
  2. vue-next仓库内部完整的测试用例。
  3. 完善的TypeScript类型支持。
  4. 完全复用@vue/reacivity实现超强的全局状态管理能力。
  5. 状态管理中组件级别的精确更新。
  6. Vue3总是要学的嘛,提前学习防止失业!

缺点:

  1. 由于需要精确的收集依赖全靠useStore,所以selector函数一定要精确的访问到你关心的数据。甚至如果你需要触发数组内部某个值的更新,那你在useStore中就不能只返回这个对象本身。

源码地址

https://github.com/sl1673495/react-composition-api

如果你喜欢这个库,欢迎给出你的star✨,你的支持就是我最大的动力~

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

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

相关文章

VS Code 变身约会利器!以码会友,轻松找到心仪的TA!

在韩老师的《Visual Studio Code 权威指南》一书中&#xff0c;我向大家推荐了许多好用的插件&#xff0c;其中也不乏许多摸鱼插件&#xff0c;刷知乎、炒股票、看电影、听音乐、追番、看小说&#xff0c;一应俱全。前不久&#xff0c;韩老师还给大家推荐过一款“小霸王”插件&…

机器学习——常用算法的总结

机器学习常用算法总结 机器学习——常用算法的总结学习方式一、监督式学习&#xff1a;1、分类2、回归补充——线性回归与逻辑回归二、非监督式学习&#xff1a;三、半监督式学习&#xff1a;四、强化学习&#xff1a;算法类似性一、回归算法&#xff1a;二、基于实例的算法三、…

bms中soh计算方式_BMS算法设计之电池SOH介绍(下)

本期咱们继续来聊聊电池包SOH的算法实现&#xff0c;本次主要聊一聊用电化学阻抗谱法&#xff0c;基于模型的估算和机械疲劳的理论方法来实现SOH的估算。上一篇文章没有看到的朋友不用着急&#xff0c;文章中会有上一篇的链接。趁着周末的大好时光&#xff0c;一起来学习下吧&a…

.NET 5 的重大改变:消失的历史技术

在本文中&#xff0c;我们将回顾一些未能进入.NET Core 的历史性.NET 技术。有趣之处在于&#xff0c;这些技术的 API 被复制过来了&#xff0c;这暗示着微软当时在考虑将来在.NET Core 中对它们进行实现。全局程序集缓存全局程序集缓存&#xff08;GAC&#xff09;背后的理论是…

机器学习——决策树学习

机器学习——决策树学习一、什么是决策树二、决策树的学习过程特征选择&#xff1a;决策树生成&#xff1a;剪枝&#xff1a;三、决策树的一个具体的实例导入数据python strip() 函数和 split() 函数的详解及实例数据处理提取到训练集中的标签给数据的每一列添加上标签&#xf…

微软:Excel公式是世界上使用最广泛的编程语言

喜欢就关注我们吧&#xff01;文|一君微软近日推出了一项 Excel 公式构建的新功能 LAMBDA&#xff0c;正则测试阶段。LAMBDA 允许使用 Excel 自身的公式语言自定义功能&#xff0c;而过去&#xff0c;Excel 中需要通过 JS 等语言编写自定义函数。同时&#xff0c;LAMBDA 还可以…

tcp unity 图片_用 Unity 做个游戏(七) - TCP Socket 客户端

前言这真的是最后一篇有关基础框架的文章了&#xff01;写到这里已经第七篇了orz之前的其实还是挺枯燥的&#xff0c;都是些基础方面的东西&#xff0c;并看不到什么有趣的内容可能是我把事情想的太复杂了吧&#xff0c;所有东西都想做到能力范围内的最好&#xff0c;尤其是这些…

机器学习——文件的读取

机器学习——文件的读取(一).txt文件的读取(二)excel文件读取操作(一).txt文件的读取 txt的链接 链接&#xff1a;https://pan.baidu.com/s/1fIAUdCDTpR7TiqLHZtx1yg 提取码&#xff1a;0929 python strip() 函数和 split() 函数的详解及实例 一直以来都分不清楚strip和split…

理解C#中的闭包

1、 闭包的含义首先闭包并不是针对某一特定语言的概念&#xff0c;而是一个通用的概念。除了在各个支持函数式编程的语言中&#xff0c;我们会接触到它。一些不支持函数式编程的语言中也能支持闭包&#xff08;如java8之前的匿名内部类&#xff09;。在看过的对于闭包的定义中&…

linux select读取节点数据失败_MySQL中覆盖索引查询和select*查询执行结果案例分析...

索引优化建议在MySQL中要尽可能使用覆盖索引进行检索&#xff0c;只访问索引的查询(索引列和查询列一致)&#xff0c;减少select * 可提高查询效率覆盖索引(Covering Index)理解方式一:就是select的数据列只用从索引中就能够取得&#xff0c;不必读取数据行&#xff0c;MySQL可…

机器学习之乳腺癌预测

机器学习之乳腺癌预测 (一)问题分析1.问题背景2.问题分析3.题目所需的代码及数据(二).导入数据1. 认识数据集2.导入数据3.数据概述(三)EDA 数据探索性分析1.描述性统计分析A.查看数据维度(行列数)B.数据统计描述(列名对应的信息)C.查看数据信息(统计学信息)D.缺失处理2.数据可视…

使用 Azure WAF 羞辱黑客的智商

点击上方蓝字关注“汪宇杰博客”导语还记得之前给大家介绍过的《使用 Azure Web 应用防火墙拦截黑客攻击》吗&#xff1f;今天我又带来了一个有趣的 Azure WAF 小技巧&#xff0c;可以让你爽一把。好奇的黑客今天 Azure Application Insights 上发现了一段集中时间的404错误&am…

实现option上下移动_用jQuery实现lt;selectgt;选项上下移动 - 不要哀求 学会争取 若是如此 终有所获 - ITeye博客...

嘖嘖嘖&#xff0c;短短兩個API串接: $opt.next().after($opt)就做出了向下移動的效果。記得以往用純Javascript寫&#xff0c;還得判斷是否為最後一個&#xff0c;若是就不能下移&#xff1b;然後上下位置交換得用options[index]搞半天。不得不要再次讚嘆jQuery的神奇!$(funct…

机器学习之乳腺癌问题(SVM)

机器学习之乳腺癌问题SVM题目所需的代码及数据利用SVM建模SVM调参题目所需的代码及数据 链接&#xff1a;https://pan.baidu.com/s/1bS7Ku_PUfcimiVkmLz9Fzw 提取码&#xff1a;0929 利用SVM建模 import matplotlib.pyplot as plt import pandas as pd import numpy as npfro…

数据科学与python语言实验——NumPy数值计算基础

NumPy数值计算基础实验数据&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1-E2ShVTdI0X5lwDtMLFFsQ 提取码&#xff1a;0929 代码实现&#xff1a; 之前不会的地方&#xff1a; 1&#xff0e;读取文件 使用numpy内置的loadtxt()函数以及这个函数的参数frame&#x…

如何将日志记录到 Windows事件日志 中

每当出现一些未捕获异常时&#xff0c;操作系统都会将异常信息写入到 Windows 事件日志 中&#xff0c;可以通过 Windows 事件查看器 查看&#xff0c;如下图&#xff1a;这篇文章将会讨论如何使用编程的方式将日志记录到 Windows 事件日志 中。安装 EventLog 要想在 .NET Core…

linux磁盘写保护怎么修改_mount: /dev/vdb 写保护,将以只读方式挂载

今天再mount磁盘的时候遇到一个问题&#xff1a;[rootoracle1 /]# mount /dev/vdb /oradatamount: /dev/vdb 写保护&#xff0c;将以只读方式挂载mount: 未知的文件系统类型“(null)”这个问题重新格式化磁盘后就好了mkfs.ext4 /dev/vdb让这个盘在系统启动的时候自动挂载[oracl…

【Java】springboot

文章目录 Spingboot1、起步依赖2、构建springboot工程jar包3、springboot配置文件4、多环境配置5、maven和boot多环境兼容问题6、配置文件分类7、springboot整合mybatis Spingboot springboot用来简化spring的初始搭建以及开发过程。 比方说&#xff0c;创建一个springmvc程序…

数据科学与python语言——Matplotlib数据可视化基础

Matplotlib数据可视化基础一.读取数据与数据处理阶段1.提取指定行中的数据2.得到>指定数值的数据3.得到指定值得数据4.整体的数据处理&#xff1a;二.画图函数1.plt.subplots()2.plt.subplots_adjust()3.设置x轴y轴的刻度和标签4.使用中文标题在作图时三.画折线图(plot)四.画…

2021年,Azure云遇到. NET5,注定开启高光时刻,微软的心,真大!

云开发诞生的市场背景云开发是一个已经存在了很多年的概念&#xff0c;但在过去未能真正成为主流。然而&#xff0c;由于云和软件即服务的宏观趋势的结合&#xff0c;以及技术的进步&#xff0c;如容器技术 Docker 和 Kubernetes&#xff0c;云开发现在有机会最终成为基于云的应…