2个版本
0.0.2 | 2024年7月21日 |
---|---|
0.0.1 | 2024年5月30日 |
#1289 in 过程宏
136 每月下载量
在 sigmut 中使用
18KB
281 行
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的严格模式下,状态计算将额外调用一次以确保遵循此规则。
在SolidJS中,在状态计算期间做出的状态变化将被延迟到状态计算完成。
在sigmut
中,使用SignalContext
和ActionContext
将状态变化和状态计算分离。
ActionContext
:用于状态变化SignalContext
:用于状态计算
通过要求执行状态变化或状态计算的功能使用相应的上下文,明确区分了状态变化和状态计算,编译器可以强制实施这种分离。
"状态变化与状态计算的分离"通过在状态计算期间将状态视为不可变来简化程序,这与Rust的所有权概念类似。内部,sigmut
使用RefCell
,但这种相似性有助于避免状态计算期间的BorrowError
。如果您正在使用许多Rc<RefCell<T>>
,切换到sigmut
可以导致更健壮的程序,并且出现BorrowError
的情况更少。
易于使用的单线程模型
sigmut
采用单线程模型的原因如下
- 简单且易于处理
- 没有死锁的风险
- 不需要同步,允许即时检索当前值
- 与
async/await
的互操作性,使多线程的优势得以体现 - 能够实现无故障(没有基于过时状态的无效计算)
支持使用 async/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 许可证定义的,您有意提交以包含在作品中的任何贡献,将如上所述双重许可,不附加任何额外条款或条件。
依赖关系
~2.3–4MB
~69K SLoC