6 个版本
0.2.4 | 2024年4月20日 |
---|---|
0.2.3 | 2024年4月12日 |
0.2.1 | 2024年3月31日 |
0.1.1 | 2023年12月30日 |
#264 in GUI
157 次每月下载
32KB
275 行
dioxus-radio 📡🦀
为 Dioxus 🧬 提供具有主题订阅系统的完全类型化全局状态管理。
适合人群
- 你需要具有嵌套响应性的全局状态
- 你真的不希望进行不必要的重新运行
- 你希望有一个精确的状态订阅系统
- 你不想不必要地克隆状态
支持
安装
安装最新版本
cargo add dioxus-radio
示例
cargo run --example demo
问题
你有一个单个的全局状态,但你的组件最终不必要地重新运行,因为尽管状态本身已更改,但并非所有组件都对新的突变状态感兴趣。相反,你希望有一个具有嵌套响应性的全局状态。
其他框架以自己的方式解决这个问题,例如,Solid 和其 Stores 允许你通过指定要突变的状态部分的路径来细粒度地突变状态,这使得 Solid 能够重新渲染读取该特定状态部分的组件。
这既不适用于 Rust 也不适用于 Dioxus,但幸运的是,有其他方法。
dioxus-radio
提供了不同的方法,为了在全局状态下实现细粒度订阅,你指明一个 Channel
,这样,每次突变状态时,只有相同 Channel
的其他订阅者会收到通知。这种特定的模式由于使用枚举作为 Channel
的方式而非常适合 Rust。
示例
让我们想象我们想要一个应用,其中可能有 N
个元素,每个元素都有自己的状态。一开始你可能认为可以在每个组件实例中使用本地信号。但这个例子有一个限制,即状态必须是全局的,以便其他组件可以读取这些 N
个元素的状态。
以下是一个示例
// Global state
#[derive(Default)]
struct Data {
pub lists: Vec<Vec<String>>,
}
// Channels used to identify the subscribers of the State
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum DataChannel {
ListCreated,
ListN(usize),
}
impl RadioChannel<Data> for DataChannel {}
fn main() {
dioxus::launch(|| {
// Initialize the global state
use_init_radio_station::<Data, DataChannel>(Data::default);
// Subscribe to the state with the channel `DataChannel::ListCreated`
// This way whenever a writer using the `DataChannel::ListCreated` mutates the state
// This component will rerun
let mut radio = use_radio::<Data, DataChannel>(DataChannel::ListCreated);
let onclick = move |_| {
radio.write().lists.push(Vec::default());
};
println!("Running DataChannel::ListCreated");
rsx!(
button {
onclick,
"Add new list",
}
for (list_n, _) in radio.read().lists.iter().enumerate() {
ListComp {
list_n
}
}
)
});
}
#[allow(non_snake_case)]
#[component]
fn ListComp(list_n: usize) -> Element {
// Subscribe the state using the `DataChannel::ListN(list_n)` channel, where `list_n` is index of this element
// Whenever a mutation (in this case just this component) occurs only
// this component will rerun as it is the only one that is subscribed to this channel
let mut radio = use_radio::<Data, DataChannel>(DataChannel::ListN(list_n));
println!("Running DataChannel::ListCreated({list_n})");
rsx!(
div {
button {
onclick: move |_| radio.write().lists[list_n].push("Hello World".to_string()),
"New Item"
},
ul {
for (i, item) in radio.read().lists[list_n].iter().enumerate() {
li {
key: "{i}",
"{item}"
}
}
}
}
)
}
起源
dioxus-radio
的想法最初起源于我在 freya-editor
的工作中。我在优化状态管理时遇到了很多不必要的重新运行,所以我开始研究主题订阅状态管理。过了一段时间,我终于意识到我可以把这个功能导出到一个独立的库中。于是,我创建了 dioxus-radio
,现在它实际上也为 freya-editor
提供了动力!
许可证
MIT 许可证
依赖关系
~4–10MB
~104K SLoC