Add lazy contexts to signals
This commit is contained in:
5 files changed
+40
-6
No files matched your search
+1
-4
@@ -1,5 +1,4 @@
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_signals::{use_init_signal_rt, use_signal};
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
@@ -7,9 +6,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
use_init_signal_rt(cx);
|
||||
|
||||
let mut count = use_signal(cx, || 0);
|
||||
let mut count = dioxus_signals::use_signal(cx, || 0);
|
||||
|
||||
use_future!(cx, || async move {
|
||||
loop {
|
||||
|
||||
@@ -418,6 +418,25 @@ impl<'src> ScopeState {
|
||||
value
|
||||
}
|
||||
|
||||
/// Provide a context to the root and then consume it
|
||||
///
|
||||
/// This is intended for "global" state management solutions that would rather be implicit for the entire app.
|
||||
/// Things like signal runtimes and routers are examples of "singletons" that would benefit from lazy initialization.
|
||||
///
|
||||
/// Note that you should be checking if the context existed before trying to provide a new one. Providing a context
|
||||
/// when a context already exists will swap the context out for the new one, which may not be what you want.
|
||||
pub fn provide_root_context<T: 'static + Clone>(&self, context: T) -> T {
|
||||
let mut parent = self;
|
||||
|
||||
// Walk upwards until there is no more parent - and tada we have the root
|
||||
while let Some(next_parent) = parent.parent {
|
||||
parent = unsafe { &*next_parent };
|
||||
debug_assert_eq!(parent.scope_id(), ScopeId(0));
|
||||
}
|
||||
|
||||
parent.provide_context(context)
|
||||
}
|
||||
|
||||
/// Pushes the future onto the poll queue to be polled after the component renders.
|
||||
pub fn push_future(&self, fut: impl Future<Output = ()> + 'static) -> TaskId {
|
||||
let id = self.tasks.spawn(self.id, fut);
|
||||
|
||||
@@ -79,3 +79,6 @@ pub use usecallback::*;
|
||||
|
||||
mod usememo;
|
||||
pub use usememo::*;
|
||||
|
||||
mod userootcontext;
|
||||
pub use userootcontext::*;
|
||||
@@ -0,0 +1,9 @@
|
||||
use dioxus_core::ScopeState;
|
||||
|
||||
///
|
||||
pub fn use_root_context<T: 'static + Clone>(cx: &ScopeState, new: impl FnOnce() -> T) -> &T {
|
||||
cx.use_hook(|| {
|
||||
cx.consume_context::<T>()
|
||||
.unwrap_or_else(|| cx.provide_root_context(new()))
|
||||
})
|
||||
}
|
||||
@@ -10,16 +10,22 @@ mod rt;
|
||||
use dioxus_core::ScopeState;
|
||||
pub use rt::*;
|
||||
|
||||
use crate::rt::claim_rt;
|
||||
|
||||
pub fn use_init_signal_rt(cx: &ScopeState) {
|
||||
cx.use_hook(|| {
|
||||
let rt = crate::rt::claim_rt(cx.schedule_update_any());
|
||||
let rt = claim_rt(cx.schedule_update_any());
|
||||
cx.provide_context(rt);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn use_signal<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal<T> {
|
||||
cx.use_hook(|| {
|
||||
let rt: &'static SignalRt = cx.consume_context().unwrap();
|
||||
let rt: &'static SignalRt = match cx.consume_context() {
|
||||
Some(rt) => rt,
|
||||
None => cx.provide_context(claim_rt(cx.schedule_update_any())),
|
||||
};
|
||||
|
||||
let id = rt.init(f());
|
||||
rt.subscribe(id, cx.scope_id());
|
||||
|
||||
|
||||
Reference in new issue
Block a user