MICRO REACTIVE
简介
一套基于Function和Proxy的响应式系统,具有vue3与solidjs的优点,弥补各自的缺点
与现有框架对比
对比vue3
在vue3中,需要考虑当前值是基础类型还是对象类型,采用不同的代理方式(ref, reactive),存在以下痛点
- 基础类型需要使用 ref.value
- reactive 对象整个替换会丢失响应式
- 对象的解构,需要包一层toRefs,显得不太方便
对比solidjs
在solidjs中,采用读写函数的方式,有效避免了vue3中的几个痛点,但同时也带来了新的问题
- 没法通过链式调用的方式直接修改对象的下级属性
- 需要通过插件的方式实现响应式对象解构
优势
micro-reactive库有效解决了上述的几个问题,有以下几个优势
- 不需要考虑变量类型,一律使用useReactive,如:const state = useReactive({ a: 1 })
- 没有ref.value的心智负担
- 对象类型可整个修改,不会丢失响应,如:state({ a: 2 })
- 响应式对象的属性仍是响应式的,可链式调用修改,如:state.a(3)
- 可任意解构且不丢失响应,如:const { a } = state; a(4)
案例
/* micro-reactive */
const data = useReactive({ id: 1, value: 0 });
// 直接修改根对象,不会丢失响应
data({ id: 2, value: 1 });
// 链式调用
data.id(3);
console.log(data()); // { id: 3, value: 1 }
// 直接解构,不需要 toRefs() 操作
const { value } = data;
value(-1);
console.log(data()); // { id: 3, value: -1 }
原理
- 使用读写函数(read and write)实现依赖的收集和触发(借鉴于solidjs)
- 对函数使用proxy代理,使函数能够达到动态获取属性的效果(借鉴于vue3)
- 变量值使用全局state加key path的方式存储(借鉴于vue2)
在框架中使用
vue3
<script setup lang="ts">
import { useReactive } from "micro-reactive";
const count = useReactive(0);
</script>
<template>
<button type="button" @click="count(count() + 1)">
count is {{ count() }}
</button>
</template>
react
import { useComputed, useReactive } from "micro-reactive";
// 引入 hack
import { defineState } from "../hacks/defineState";
export default function Counter() {
// useReactive 声明变量需写在 defineState 中
const [count] = defineState(() => [useReactive(0)]);
// 计算属性
const double = useComputed(() => count() * 2);
return (
<button onClick={() => count(count() + 1)}>
double count is {double()}
</button>
);
}
solidjs
import { useReactive } from "micro-reactive";
export default function Counter() {
const count = useReactive(0);
return (
<button type="button" onClick={() => count(count() + 1)}>
count is {count()}
</button>
);
}
代码仓库
更多使用方式及详细信息请查看 github地址
交流
- qq群:342 479 487
题外话
关于本库的一些灵感,不仅源自于solidjs和vue3,还来源于我一年前参加校招时的一道面试题,有兴趣的可以试试看哦。
/**
* 有如下对象data
* 现需要将 data 转换为另一个数据结构 state
* 且满足以下要求
* 1. state() == { a: { b: { c: 1 } } }
* 2. state.a() == { b: { c: 1 } }
* 3. state.a.b() == { c: 1 }
* 4. state.a.b.c() == 1
* 5. state.a.b.d() == undefined
* 6. state.a.e.f() == undefined
* 7. state.g(4) == 4
*/
const data = { a: { b: { c: 1 } } }
function transform(data) {
}