简体中文 | [English](./README.en.md)
# helux 简介
[helux](https://github.com/heluxjs/helux) 是一个集`atom`、`signal`、`依赖收集`、`派生`、`观察`为一体,支持细粒度响应式更新的状态引擎,支持所有类 react 框架(包括 react 18)
- [Doc](https://heluxjs.github.io/helux)
- [Playground](https://heluxjs.github.io/helux/playground)
- [Helux-react-starter](https://codesandbox.io/p/sandbox/helux-react-starter-ts-539scq)
- [Helux-openinula-starter](https://codesandbox.io/p/devbox/helux-openinula-66gfj2)
- [Helux-preact-starter](https://codesandbox.io/p/sandbox/helux-preact-starter-dnyzpy)
- [Helux-nextjs-starter](https://github.com/heluxjs/helux-nextjs-starter)
特性简介:
- 内置依赖追踪特性,基于最快的不可变 js 库[limu](https://github.com/tnfe/limu)开发,拥有超强性能
- `atom` 支持任意数据结构且自带依赖收集功能, 无需拆分很细,天然对 DDD 领域驱动设计友好
- 内置 `signal` 响应机制,实现 0 hook 编码 dom 粒度或块粒度的更新
- 内置 `loading` 模块,可管理所有异步任务的运行状态、并捕捉错误抛给组件、插件
- 内置 `sync` 系列 api,支持**双向绑定**,轻松应对表单处理
- 内置 `reactive` 响应式对象,支持数据变更直接驱动关联 ui 渲染
- 内置 `define` 系列 api,方便对状态模块化抽象,轻松驾驭大型前端应用架构
- 内置事件系统
- 支持可变派生,适用于当共享对象 a 部分节点变化需引起其他节点自动变化的场景,数据更新粒度更小
- 支持全量派生,适用于不需要对数据做细粒度更新的场景
- 全量派生、可变派生均支持异步任务
- 全量派生、可变派生除数据变更驱动执行外,还支持人工重新触发运行
- 支持中间件、插件系统,可无缝对接 redux 生态相关工具库
- 100% ts 编码,类型安全
> 为了方便用户理解`helux`核心逻辑,我们提供了[how-helux-was-born](https://github.com/fantasticsoul/how-helux-was-born)项目用于辅助用户做 helux 源码调试。
## 30s 上手
使用 npm 命令`npm i helux`安装`helux`,然后调用`atom`创建共享状态,调用`useAtom`使用共享状态,that's all,你已接入`helux`来提升局部状态为共享状态. ✨
```diff
import React from 'react';
+ import { atom, useAtom } from 'helux';
+ const [sharedState] = atom({ a: 100, b: { b1: 1 } });
function HelloHelux(props: any) {
- const [state, setState] = React.useState({ a: 100, b: { b1: 1, b2: 2 } });
+ const [state, setState] = useAtom(sharedState);
- const change = setState((prev) => ({ ...prev, b: { ...prev.b, b1: 100 } }));
+ const change = setState((draft) => { draft.b.b1 = 100 });
// 收集到当前组件依赖为 a,仅当 a 变更时才触发重渲染
return {state.a}
;
}
```
## 类 pinia 使用
基于 helux 向上封装了[@helux/store-pinia](https://github.com/heluxjs/helux/tree/master/packages/helux-store-pinia),你可以像 pinia 一样管理 react 状态了,访问[示例](https://codesandbox.io/p/sandbox/helux-store-pinia-forked-xqw3ks?file=%2Fsrc%2FLikePinia.tsx)体验.
```tsx
import { defineStore } from '@helux/store-pinia';
const counterStoreCtx = defineStore('Counter', {
state: () => ({ count: 1, mountCount: 1 }),
getters: {
// 由 state 派生出 double ,上游依赖不变化时此函数不再重复计算
double() {
return this.count * 2;
},
// 由其他 getters 派生出 plus10 ,上游依赖不变化时此函数不再重复计算
plus10() {
return this.double + 10;
},
},
actions: {
// 同步方法
changeCount(payload: number) {
this.count = payload;
},
// 异步方法
async changeCountSync(p1: number, p2: number) {
this.changeCount(p1);
await delay();
this.count += p2;
},
plus() {
this.count += 1;
},
},
// lifecyle 里可以访问 actions 调用方法
// lifecycle的方法由框架负责调用,在 actions 里是访问不到的(类型上已屏蔽),由框架负责调用
lifecycle: {
mounted() {
// this.changeCount(888);
this.mountCount += 1;
},
},
});
```
具体使用方式可参考[文档](https://github.com/heluxjs/helux/tree/master/packages/helux-store-pinia)
## 部分特性简介
以下是一些常见特性,更多特性可查阅文档里的[Atom](https://heluxjs.github.io/helux/guide/atom)、[Signal](https://heluxjs.github.io/helux/guide/signal)、[依赖追踪](https://heluxjs.github.io/helux/guide/dep-tracking)、[响应式](https://heluxjs.github.io/helux/guide/reactive)、[双向绑定](https://heluxjs.github.io/helux/guide/sync)、[派生](https://heluxjs.github.io/helux/guide/derive)、[观察](https://heluxjs.github.io/helux/guide/watch)、[Action](https://heluxjs.github.io/helux/guide/action)、[模块化](https://heluxjs.github.io/helux/guide/modular) 等章节做深入了解
### atom
```tsx
import { atom, useAtom } from 'helux';
const [numAtom] = atom(1); // { val: 1 }
function Demo() {
const [num, setAtom] = useAtom(numAtom); // num 自动拆箱
return {num}
;
}
```
### dep tracking
**依赖追踪**,组件渲染期间将实时收集到数据依赖
```tsx
import { useAtom } from 'helux';
const [objAtom, setObj] = atom({ a: 1, b: { b1: 1 } });
// 修改草稿,生成具有数据结构共享的新状态,当前修改只会触发 Demo1 组件渲染
setObj((draft) => (draft.a = Math.random()));
function Demo1() {
const [obj] = useAtom(objAtom);
// 仅当 obj.a 发生变化时才触发重渲染
return {obj.a}
;
}
function Demo2() {
const [obj] = useAtom(objAtom);
// 仅当 obj.b.b1 发生变化时才触发重渲染
return {obj.b.b1}
;
}
```
### signal
**信号响应**,可将共享状态原始值直接绑定到视图
原始值响应
```tsx
// 只会引起h1标签内部重渲染
{$(numAtom)}
// 格式化
{$(numAtom, num=>`hi helux ${num.val}`)}
{$(numAtom.val, num=>`hi helux ${num}`)}
```
块响应
```tsx
import { block } from 'helux';
const [objAtom] = atom({ a: 1, b: { b1: 1 } });
const UserBlock = block(() => (
{objAtom.a}
{objAtom.b.b1}
));
// 依赖是 obj.val.a, obj.val.b.b1
;
// 如使用 share 创建共享对象,则 UserBlock 实例的依赖是 obj.a, obj.b.b1
const [objAtom] = share({ a: 1, b: { b1: 1 } });
```
### mutate derive
**可变派生**,响应共享状态自身某些节点变化,派生自身其他节点结果
```ts
import { share, mutate } from 'helux';
const [shared] = share({ a: 1, b: 0, c: 0 });
mutate(shared)({
changeB: (draft) => (draft.b = shared.a + 1),
changeC: (draft) => (draft.c = shared.a + 2),
});
```
响应其他共享状态某些节点变化,派生自身其他节点结果
```ts
import { share, mutate } from 'helux';
const [shared] = share({ a: 1 });
const [sharedB] = share({ b: 0, c: 0 });
mutate(sharedB)({
changeB: (draft) => (draft.b = shared.a + 1),
changeC: (draft) => (draft.c = shared.a + 2),
});
```
### full derive
**全量派生**,响应其他共享状态某些节点变化,全量派生新结果
```ts
import { share, derive, deriveAtom, useDerived, useDerivedAtom } from 'helux';
const [shared] = share({ a: 1 });
const resultDict = derive(() => ({ num: shared.a + 100 })); // { num: number }
const resultAtom = deriveAtom(() => shared.a + 100); // 自动装箱:{ val: number }
const [result] = useDerived(resultDict); // { num: number}
const [result] = useDerivedAtom(resultAtom); // 自动拆箱:number
```
### watch
通过 watch 观察数据变化
主动定义依赖,首次不执行
```ts
import { watch } from 'helux';
// 仅观察到a变化才通知回调执行
watch(() => {
console.log('a change');
}, [shared.a]);
// shared任意节点变化就通知回调执行
watch(() => {
console.log('shared change');
}, [shared]);
```
设置 `immediate=true`,立即执行,自动收集到依赖
```ts
watch(
() => {
console.log('a change', shared.a);
},
{ immediate: true },
);
```
## 📦 了解更多
欢迎入群了解更多,由于微信讨论群号 200 人已满,需加作者微信号或 qq 群号,再邀请你如`helux & hel`讨论群(加号时记得备注 helux 或 hel)
## ❤️🔥 赞赏
小小鼓励,给予我们更多力量坚持做出更好的开源项目