#状态管理 #UI 框架 #响应式 #信号 #信号

sigmut

一个设计为 UI 框架基础的状态管理框架

2 个版本

0.0.2 2024 年 7 月 21 日
0.0.1 2024 年 5 月 30 日

#6#信号

Download history 84/week @ 2024-05-24 45/week @ 2024-05-31 6/week @ 2024-06-07 3/week @ 2024-06-14 109/week @ 2024-07-19 9/week @ 2024-07-26

118 每月下载量

MIT/Apache

240KB
7K SLoC

sigmut

Crates.io Docs.rs Actions Status

sigmut 是一个设计为 UI 框架基础的状态管理框架。

[!WARNING] 警告:此软件包仍处于非常早期的发展阶段。API 将会改变。文档较少。

功能

  • 基于信号的 API
  • "状态变化" 和 "状态计算" 的分离
  • 易于使用的单线程模型
  • 支持使用 async/await 进行异步操作
  • 无错误(不基于过时状态进行不必要的计算)
  • 能够实现更高效的响应式原语

基于信号的 API

sigmut 中,状态管理是通过以下响应式原语进行的

  • State<T>:类似于 Rc<RefCell<T>>,但增加了观察变化的额外功能。
  • Signal<T>:类似于 Rc<dyn Fn() -> &T>,但增加了观察结果变化的额外功能。
  • effect:一个在相关状态发生变化时再次被调用的函数。
use sigmut::{Signal, State};

let mut rt = sigmut::core::Runtime::new();

let a = State::new(0);
let b = State::new(1);
let c = Signal::new({
    let a = a.clone();
    let b = b.clone();
    move |sc| a.get(sc) + b.get(sc)
});
let _e = c.effect(|x| println!("{x}"));

rt.update(); // prints "1"

a.set(2, rt.ac());
rt.update(); // prints "3"

a.set(3, rt.ac());
b.set(5, rt.ac());
rt.update(); // prints "8"

状态之间的依赖关系将自动跟踪,当发生更改时,将自动触发重新计算。

这种机制是最近的一个趋势,也被其他状态管理库所采用,如下所示

"状态变化" 和 "状态计算" 的分离

许多状态管理库通过将状态变化与状态计算分离来简化程序。

Elm 中,模型-视图-更新 架构将状态变化(更新)与状态计算(视图)分离。

React 中,关于 Components and Hooks must be pure 的规则禁止在状态计算期间进行状态更改。在 React 的 StrictMode 中,状态计算会额外调用一次以确保遵循此规则。

SolidJS 中,在状态计算期间做出的状态更改将被 延迟到状态计算完成

sigmut 中,状态更改和状态计算是通过使用 SignalContextActionContext 来分开的。

通过要求执行状态更改或状态计算的函数使用相应的上下文,可以清楚地区分状态更改和状态计算,编译器可以强制执行这种分离。

"状态更改和状态计算分离" 通过在状态计算期间将状态视为不可变来简化程序,这与 Rust 的所有权概念类似。内部,sigmut 使用 RefCell,但这种相似性有助于在状态计算期间避免 BorrowError。如果您正在使用许多 Rc<RefCell<T>>,切换到 sigmut 可以导致程序更健壮,BorrowError 的发生次数更少。

易于使用的单线程模型

sigmut 采取单线程模型的原因如下

  • 简单且易于处理
  • 没有死锁的风险
  • 不需要同步,可以即时检索当前值
  • async/await 兼容,从而实现多线程的优点
  • 能够实现无故障(没有基于过时状态的无关计算)

支持使用 async/await 进行异步操作

sigmut 集成了 async/await,允许将异步操作视为同步的 Poll<T> 状态。这使得它可以与异步运行时,如 tokio 兼容。

有关更多详细信息,请参阅包含 asyncfuturestream 的名称的函数和类型。

无错误(不基于过时状态进行不必要的计算)

一些状态管理库在状态计算时使用过时的缓存,这可能导致意外的结果。虽然这些意外的结果会被快速重新计算,并且无意计算的结果会被丢弃,但这仍然可能引发问题,包括潜在的恐慌。因此,仅仅因为进行了重新计算,并不能完全解决问题。

sigmut 中,缓存通过将其分为三种类型来管理:cleandirtymaybe dirty。通过一致且准确地检查这些缓存的合法性,sigmut 避免了在状态计算时使用过时缓存所引起的问题。

能够实现更高效的响应式原语

sigmut 包含一个低级模块,sigmut::core,它仅处理状态变更通知。通过使用此模块,您可以在特定条件下实现更高效的响应式原语。

这个实现的例子是 SignalVec<T>SignalVec<T>Signal<Vec<T>> 类似,但它允许您获取自上次访问以来的更改历史,从而实现更高效的处理。

许可证

本项目采用 Apache-2.0/MIT 双许可协议。请参阅两个 LICENSE-* 文件以获取详细信息。

贡献

除非您明确表示,否则,您按照 Apache-2.0 许可证定义的任何有意提交以包含在作品中的贡献,将按照上述方式双许可,不附加任何额外条款或条件。

依赖项

~3.5–5.5MB
~103K SLoC