Last active
July 11, 2023 19:09
-
-
Save ealmloff/74301fde7f6120d1b1b06adc7e6c40ea to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![allow(non_snake_case)] | |
use dioxus::prelude::*; | |
use std::cell::{Ref, RefCell, RefMut}; | |
use std::collections::HashSet; | |
use std::fmt::Display; | |
use std::rc::Rc; | |
#[derive(Clone)] | |
struct SplitSubscriptions { | |
a: LocalSubscription<i32>, | |
b: LocalSubscription<i32>, | |
} | |
fn use_split_subscriptions_root(cx: &ScopeState) -> &SplitSubscriptions { | |
use_context_provider(cx, || { | |
let a = LocalSubscription::create(cx, 0); | |
let b = LocalSubscription::create(cx, 0); | |
SplitSubscriptions { a, b } | |
}) | |
} | |
fn use_split_subscriptions(cx: &ScopeState) -> &SplitSubscriptions { | |
use_context(cx).expect("No SplitSubscriptions found") | |
} | |
fn main() { | |
dioxus_desktop::launch(app); | |
} | |
fn app(cx: Scope) -> Element { | |
println!("app rendered"); | |
// This does not subscribe to the any state | |
let state = use_split_subscriptions_root(cx); | |
// This subscribes to just the state of `a` | |
let count = state.a.use_state(cx); | |
cx.render(rsx! { | |
h1 { "High-Five counter1: {count}" } | |
button { onclick: move |_| *count.write() += 1, "Up high!" } | |
button { onclick: move |_| *count.write() -= 1, "Down low!" } | |
Comp {} | |
}) | |
} | |
fn Comp(cx: Scope) -> Element { | |
println!("comp rendered"); | |
let state = use_split_subscriptions(cx); | |
let count = state.b.use_state(cx); | |
cx.render(rsx! { | |
h1 { "High-Five counter2: {count}" } | |
button { onclick: move |_| *count.write() += 1, "Up high!" } | |
button { onclick: move |_| *count.write() -= 1, "Down low!" } | |
}) | |
} | |
#[derive(Clone)] | |
pub struct LocalSubscription<T> { | |
inner: Rc<RefCell<T>>, | |
subscribed: Rc<RefCell<HashSet<ScopeId>>>, | |
update: Rc<dyn Fn()>, | |
} | |
impl<T: 'static> LocalSubscription<T> { | |
pub fn create(cx: &ScopeState, inner: T) -> Self { | |
let inner = Rc::new(RefCell::new(inner)); | |
let update_any = cx.schedule_update_any(); | |
let subscribed: Rc<RefCell<HashSet<ScopeId>>> = Default::default(); | |
let update = Rc::new({ | |
to_owned![subscribed]; | |
move || { | |
for id in subscribed.borrow().iter() { | |
update_any(*id); | |
} | |
} | |
}); | |
Self { | |
inner, | |
subscribed, | |
update, | |
} | |
} | |
pub fn use_state<'a>(&self, cx: &'a ScopeState) -> &'a UseLocal<T> { | |
cx.use_hook(|| { | |
let id = cx.scope_id(); | |
self.subscribed.borrow_mut().insert(id); | |
UseLocal { | |
inner: self.inner.clone(), | |
update: self.update.clone(), | |
} | |
}) | |
} | |
pub fn use_write_only<'a>(&self, cx: &'a ScopeState) -> &'a LocalWrite<T> { | |
cx.use_hook(|| LocalWrite { | |
inner: self.inner.clone(), | |
update: self.update.clone(), | |
}) | |
} | |
// This should only be used outside of components. This will not subscribe to any state. | |
pub fn write(&self) -> RefMut<T> { | |
(self.update)(); | |
self.inner.borrow_mut() | |
} | |
// This should only be used outside of components. This will not subscribe to any state. | |
pub fn read(&self) -> Ref<T> { | |
self.inner.borrow() | |
} | |
} | |
/// A read/write version of the local state. This allows mutating the state and reading state. | |
pub struct UseLocal<T> { | |
inner: Rc<RefCell<T>>, | |
update: Rc<dyn Fn()>, | |
} | |
impl<T> UseLocal<T> { | |
pub fn read(&self) -> Ref<T> { | |
self.inner.borrow() | |
} | |
pub fn write(&self) -> RefMut<T> { | |
(self.update)(); | |
self.inner.borrow_mut() | |
} | |
} | |
impl<T: Display> Display for UseLocal<T> { | |
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
self.inner.borrow().fmt(f) | |
} | |
} | |
/// A write only version of the local state. This only allows mutating the state, not reading state because you can only access the inner type in a impl Fn(&mut T) closure. | |
pub struct LocalWrite<T> { | |
inner: Rc<RefCell<T>>, | |
update: Rc<dyn Fn()>, | |
} | |
impl<T> LocalWrite<T> { | |
pub fn with_mut(&self, f: impl Fn(&mut T)) { | |
f(&mut *self.inner.borrow_mut()); | |
(self.update)(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment