2 个版本
0.0.2 | 2024 年 7 月 21 日 |
---|---|
0.0.1 | 2024 年 5 月 30 日 |
#6 在 #信号
118 每月下载量
240KB
7K SLoC
sigmut
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
中,状态更改和状态计算是通过使用 SignalContext
和 ActionContext
来分开的。
ActionContext
:用于状态更改SignalContext
:用于状态计算
通过要求执行状态更改或状态计算的函数使用相应的上下文,可以清楚地区分状态更改和状态计算,编译器可以强制执行这种分离。
"状态更改和状态计算分离" 通过在状态计算期间将状态视为不可变来简化程序,这与 Rust 的所有权概念类似。内部,sigmut
使用 RefCell
,但这种相似性有助于在状态计算期间避免 BorrowError
。如果您正在使用许多 Rc<RefCell<T>>
,切换到 sigmut
可以导致程序更健壮,BorrowError
的发生次数更少。
易于使用的单线程模型
sigmut
采取单线程模型的原因如下
- 简单且易于处理
- 没有死锁的风险
- 不需要同步,可以即时检索当前值
- 与
async/await
兼容,从而实现多线程的优点 - 能够实现无故障(没有基于过时状态的无关计算)
支持使用 async/await
进行异步操作
await
进行异步操作sigmut
集成了 async/await
,允许将异步操作视为同步的 Poll<T>
状态。这使得它可以与异步运行时,如 tokio
兼容。
有关更多详细信息,请参阅包含 async
、future
或 stream
的名称的函数和类型。
无错误(不基于过时状态进行不必要的计算)
一些状态管理库在状态计算时使用过时的缓存,这可能导致意外的结果。虽然这些意外的结果会被快速重新计算,并且无意计算的结果会被丢弃,但这仍然可能引发问题,包括潜在的恐慌。因此,仅仅因为进行了重新计算,并不能完全解决问题。
在 sigmut
中,缓存通过将其分为三种类型来管理:clean
、dirty
和 maybe 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