@embra/reactivity

中文文档
0.0.8发布于 2026/04/08MITTypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 1.2万

一种轻量级,可堆肥和明显的反应系统.

中文使用文档
文档目录12 节
  1. 特征
  2. 完全反应 没有代理,没有魔法.
  3. 明确的反应。 没有隐藏的依赖,没有惊喜.
  4. QQ零成本所有制模式. 类型安全生命周期管理.
  5. 国家与行动的灵活抽象.
  6. QQ 控制更新的调度机制 .
  7. 框架不可知论。 头等支持回放.
  8. 小捆绑大小。 注重表现和简洁.
  9. 安装
  10. 调试
  11. 追踪
  12. Chrome Devtools 自定义格式

@embra/反应

Docs Build Status npm-version Coverage Status

一种轻量级,可堆肥和明显的反应系统.

特征

完全反应 没有代理,没有魔法.

它不将数值转换为 Object.defineProperty 也没有 Proxy. 将一切保持为平版JavaScript值使得与其他库一起工作更加容易,并方便JavaScript引擎优化.

import { writable, readable, type Readable } from "@embra/reactivity";

const count$ = writable(0);
count$.set(1);

const [count2$, setCount] = readable(0);
setCount(1);

明确的反应。 没有隐藏的依赖,没有惊喜.

与基于信号的库不同, @embra/reactivity 不自动跟踪依赖关系。 您明确定义了观看的内容以及如何对变化作出反应。 这一点比较容易说明依赖性,也减少了复杂隐含依赖性计算的成本.

使用类似回放钩子的API,计算可以是更能与一般非回放函数相兼容的纯函数.

import { writable, derive } from "@embra/reactivity";

const count$ = writable(0);

const isPositive = (value: number): boolean => value > 0;

const positiveCount$ = derive(count$, isPositive);

可使用 get 内 compute 或者说 watch。 。 。 .

import { writable, compute, watch } from "@embra/reactivity";

const count$ = writable(0);
const doubleCount$ = compute(get => get(count$) * 2);

watch(get => {
  const count = get(count$);
  console.log(`Count is ${count}, double is ${get(doubleCount$)}`);
});

QQ零成本所有制模式. 类型安全生命周期管理.

实际上,我们在反应库中遇到的最大问题之一是反应值的生命周期管理. 单位 @embra/reactivity,反应依赖性被弱地引用,所以一般不需要手动处理. 然而,明确的生命周期管理仍然是避免出乎意料的行为的良好做法.

@embra/reactivity 提供零成本所有权模式,允许您创建具有明确所有权的被动值.

默认情况下,创建的活性值与类型 OwnedReadable 或者说 OwnedWritable,它暴露一个 dispose() 清除用户的方法。 当将被动值传递到其他模块时,您可以使用 Readable 或者说 Writable 类型来隐藏 dispose() 方法,确保不意外地处理该值.

import { writable, readable, type Readable, type OwnedWritable } from "@embra/reactivity";

const count$: OwnedWritable<number> = writable(0);
count$.set(1);

// Hide the setter by typing
function logCount(count$: Readable<number>) {
  count$.subscribe(console.log);

  // @ts-expect-error
  count$.set(2);
}
logCount(count$);

// Hide the setter in runtime
const [count2$, setCount] = readable(0);
setCount(1);

// @ts-expect-error
count2$.set(2);

国家与行动的灵活抽象.

在"Flux reductioner"模式的年代,我们经常使用单商店来持有状态和动作来改变状态. 这对关于该州的推理是不错的,但也引入了许多锅炉板代码.

后来,引入了状态和动作粘合在一起的模式,比如 redux-actions。 。 。 . @embra/reactivity 通过简单而灵活地抽象国家与行动,进一步推进这一步.

在下面的例子中,我们创建了Writable count$ 这看起来像一个 Writable<number>,但内部来源于更大的应用状态 appState$。这使其他模块依赖于 Writable<number> 并不知道申请状态的细节.

import { writable, derive, toWritable } from "@embra/reactivity";
import { trace } from "@embra/reactivity/debug";

const appState$ = writable({
  count: 0,
  user: null,
});

const count$ = toWritable(
  derive(appState$, state => state.count),
  count => appState$.set({ ...appState$.value, count }),
);

// when debugging, you can trace the reactive value
trace(count$);

QQ 控制更新的调度机制 .

@embra/reactivity 包括调度器机制和内置调度器,允许您在被动更新处理时进行控制. 这对批量更新和推迟计算很有用.

import { writable, MicrotaskScheduler } from "@embra/reactivity";

const rapidChangeCount$ = writable(0);

rapidChangeCount$.reaction(console.log, MicrotaskScheduler);

count$.set(1);
count$.set(2);

await Promise.resolve();
// Logs "2" once after a microtask tick, reducing unnecessary computations.

您也可以轻松提供您自定义的调度器功能 .

import { writable, asyncScheduler } from "@embra/reactivity";

const MicrotaskScheduler = asyncScheduler(flush => Promise.resolve().then(flush));
const AnimationFrameScheduler = asyncScheduler(requestAnimationFrame);

框架不可知论。 头等支持回放.

@embra/reactivity 被设计为框架不可知论。 它可用于支持JavaScript的任何框架或库. 它还为React提供一等支持.

  • 作为组件道具的活性值只是简单而高效.
    • value =: Readable
    • value + 键 onChange =: Writable
    • state + 键 action =: toWritable(derive(rootState$, selector), action) (见 国家与行动(中文(简体) )
  • 在道具下传回反应值时,可以避免出很多回放. 您只需要订阅组件中实际使用的活性值 .
import { writable } from "@embra/reactivity";
import { useValue, useDerived, useCombined } from "@embra/reactivity/react";

const count$ = writable(0);

function Counter({ count$ }) {
  const count = useValue(count$);
  const countDouble = useDerived(count$, count => count * 2);
  return (
    <div>
      <button onClick={() => count$.set(count - 1)}>-</button>
      <span>{count}</span>
      <button onClick={() => count$.set(count + 1)}>+</button>
      <span>{countDouble}</span>
    </div>
  );
}

小捆绑大小。 注重表现和简洁.

export size

安装

npm add @embra/reactivity

调试

追踪

@embra/reactivity 页:1 trace() 函数帮助调试反应值和手表。 它跟踪价值和依赖性的变化,并将其记录到控制台.

import { writable, watch } from "@embra/reactivity";
import { trace } from "@embra/reactivity/debug";

const count$ = writable(0);

// trace a reactive value
trace(count$);

// trace a watch function
watch(trace(get => get(count$)));

count$.set(1);

Chrome Devtools 自定义格式

@embra/reactivity 支持 Chrome DevTools 软件 自定义格式化。您可以通过检查 DevTools 常规设置中的“ Console” 部分中的“ 可启用自定义格式化器” 选项来启用它.

它默认在开发中启用。 您也可以通过呼叫手动启用 customFormatter()。 。 。 .

import { customFormatter } from "@embra/reactivity/debug";
customFormatter();

版本与发布记录

@embra/reactivity 共发布 8 个版本,首次发布于 2025/08/02;过去 12 个月发布了 2 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.0.8latest2026/04/087 个月前
0.0.72025/11/1811 个月前
0.0.62025/11/051 年前
0.0.52025/11/051 年前
0.0.42025/09/031.2 年前
0.0.32025/08/271.2 年前

关于 @embra/reactivity 的常见问题

@embra/reactivity 是什么?

一种轻量级,可堆肥和明显的反应系统.

如何安装 @embra/reactivity?

在项目目录运行 npm install @embra/reactivity,或使用 pnpm add / yarn add / bun add。

@embra/reactivity 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@embra/reactivity 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@embra/reactivity 可以商用吗?

@embra/reactivity 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@embra/reactivity 的下载量有多少?

根据 npm 官方下载统计,@embra/reactivity 在 2026/10/14 – 2026/11/12 这 30 天内被下载 12,290 次,日均约 410 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@embra/reactivity 还在维护吗?

最新版本 0.0.8 发布于 2026/04/08(7 个月前);至今共发布 8 个版本,其中过去 12 个月发布了 2 个;首次发布于 2025/08/02。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。