一款同时具有vue3与solidjs响应式特点的库,micro-reactive初体验

355 阅读2分钟

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) {

}