2 unstable releases
1.1.1 |
|
---|---|
1.0.1 |
|
0.3.0 | Jan 14, 2023 |
0.2.4 | Sep 24, 2022 |
#1087 in Rust patterns
80KB
1.5K
SLoC
Dioxus Shareables
dioxus-shareables
adds hooks for sharing structures between dioxus
components. Version 0.2.x provides three interfaces:
-
The
shareable!()
macro creates a single shared value.use dioxus::prelude::*; use dioxus_shareables::shareable; shareable!(Var: usize = 900); #[allow(non_snake_case)] pub fn Reader(cx: Scope) -> Element { let r = *Var.use_rw(&cx).read(); // this component will update when Var changes. // ... } #[allow(non_snake_case)] pub fn Writer(cx: Scope) -> Element { let w1 = Var.use_w(&cx); // this component writes to Var, but does not get updated when Var // changes // ... }
-
A
List
provides an array of shared values. Using aList<T>
rather than aVec<T>
allows components which use only one or two list items to get updated only when the specific list items they use are changed.use dioxus::prelude::*; use dioxus_shareables::{shareable, List, ListEntry}; shareable!(Numbers: List<usize> = [3, 5, 7].into_iter().collect()); #[allow(non_snake_case)] fn IterateOverNumbers(cx: Scope) -> Element { let nums = Numbers.use_rw(&cx); // This component is updated when new items are added to or // removed from the list, but not when the individual list // items change. let w = nums.clone(); cx.render(rsx! { ul { nums.read().iter().map(|n| rsx! { ReadANumber { num: n } }) } }) } #[allow(non_snake_case)] #[inline_props] fn ReadANumber(cx: Scope, num: ListEntry<usize>) -> Element { let num = num.use_rw(&cx); // This component is updated when this specific entry in the // list is modified, but not when the others are. ... }
List
is aVec
internally, and the methods it implements therefore get their names and behavior fromVec
. -
The
shareable_struct!{}
macro provides a sharedstruct
with interfaces that encapsulate different behavior. The idea is that each field of the struct will be stored in a separate global, and loaded only when requested. The actions block describes possible ways of using the struct in terms of what type of access (W
orRW
) they need to fields of the struct. The struct can then be initialized using an "action" which describes which fields we need which type of access to.use dioxus::prelude::*; dioxus_shareables::shareable_struct! { pub struct Fuzzy { wuzzy: u8 = 17, was_a: u16 = 59, was_he: &'static str = "bear?", } action WAS impl pub WasTrait = W[was_a, was_he]; // declares a WAS action constant, as well an // equivalent trait. action INIT = W[wuzzy, was_a] RW[was_he]; // declares the INIT constant, but no // equivalent trait. } impl<A: FuzzyActions> Fuzzy<A> { pub fn method(&self) where A: WasTrait { let me = self.with_actions(WAS); // Pending updates to the rust trait system, we // have to typecast here to get a Fuzzy<WAS>. *me.was_he().write() = "bare!"; // We have access to was_he // self.wuzzy(); // but this would fail because we don't have access to wuzzy. // ... } } // ... fn component(cx: Scope) -> Element { let fuzzy = Fuzzy::use_(&cx, INIT); // This creates the hooks for the struct and initializes it // from the necessary globals. // ... fuzzy.method(); // This is ok, since the INIT action includes everything the WAS action does. // ... cx.render(rsx!{div{}}) }
A note on version numbers.
If you're looking at the versions on Crates.io, you might notice that there the first release was a version 1.0. The simple version of the story is that I'm new to sharing my code with others and did not think about semver. Since then I've yanked all the release versions to sync the version numbers on this crate with the latest dioxus prerelease version.
Dependencies
~2.4–8MB
~52K SLoC