3 个版本

0.1.0-preview 2024年4月28日
0.1.0-beta22024年8月15日
0.1.0-beta2024年7月24日
0.1.0-alpha2024年6月28日

#235算法

Download history 43/week @ 2024-05-02 20/week @ 2024-05-09 32/week @ 2024-05-16 41/week @ 2024-05-23 67/week @ 2024-05-30 40/week @ 2024-06-06 46/week @ 2024-06-13 22/week @ 2024-06-20 139/week @ 2024-06-27 32/week @ 2024-07-04 23/week @ 2024-07-11 98/week @ 2024-07-18 163/week @ 2024-07-25 120/week @ 2024-08-01 120/week @ 2024-08-08 263/week @ 2024-08-15

739 每月下载量
2 个包中使用(通过 tachys

MIT 许可证

415KB
8K SLoC

一个细粒度反应式系统的实现。

细粒度反应性是一种通过组合三类反应式原语来建模交互式应用程序中数据流的方法

  1. 信号:原子状态单元,可以直接修改。
  2. 计算:导出值,不能直接修改,但每当它们依赖的信号发生变化时都会更新。这包括同步和异步导出值。
  3. 效果:副作用,将反应式系统与非反应式外部世界同步。

信号和计算是反应图中的“源”节点,因为观察者可以订阅它们以响应它们值的更改。效果和计算是“订阅者”节点,因为它们可以监听其他值的更改。

use reactive_graph::{
    computed::ArcMemo,
    effect::Effect,
    prelude::{Read, Set},
    signal::ArcRwSignal,
};

let count = ArcRwSignal::new(1);
let double_count = ArcMemo::new({
    let count = count.clone();
    move |_| *count.read() * 2
});

// the effect will run once initially
Effect::new(move |_| {
    println!("double_count = {}", *double_count.read());
});

// updating `count` will propagate changes to the dependencies,
// causing the effect to run again
count.set(2);

这种反应性被称为“细粒度”,因为更新信号值只会影响依赖其值的效果和计算,而不需要对其他值进行任何差异或更新计算。

此模型特别适合构建用户界面,即可以从许多不同入口点开始更改的长生命期系统。在“一次性”程序(如 CLI)中并不特别有用。

设计原则和假设

  • 效果是昂贵的。 该库基于这样的假设,即副作用(进行网络请求、将内容渲染到 DOM、写入磁盘)比传播信号更新贵得多。因此,算法设计旨在避免不必要地重新运行副作用,并愿意为此目标牺牲一点原始的更新速度。
  • 自动依赖跟踪。依赖项不是作为编译时列表指定,而是在运行时跟踪。这反过来又使 动态依赖跟踪 成为可能:订阅者在运行之间取消订阅其来源,这意味着包含条件分支的订阅者在依赖项更新时不会重新运行,而这些依赖项仅在非活动分支中使用。
  • 异步效果调度。效果作为异步任务生成。这意味着更新信号会立即更新其值,但依赖于它的效果将不会在异步运行时的下一个“tick”之前运行。(这反过来又意味着反应式系统是 异步运行时无关的:它可以在浏览器中使用 wasm-bindgen-futures,在本地二进制文件中使用 tokio,在GTK应用程序中使用 glib,等等。)

此crate中使用的反应式图算法基于 Reactively,如 这篇文章 所述。

依赖项

~1.7–4.5MB
~86K SLoC