Merge pull request #1193 from DioxusLabs/jk/re-add-root-context

Re-add provide_root_context for lazy singleton initialization
This commit is contained in:
Jonathan Kelley authored and GitHub committed 2023-07-14 13:32:53 -07:00
commit 7ab9115067
6 files changed
+46 -10

No files matched your search

+1 -4
View File
@@ -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 {
+6 -4
View File
@@ -1,5 +1,3 @@
use std::borrow::Borrow;
use dioxus_core_macro::*;
#[test]
@@ -20,8 +18,8 @@ fn formatting_compiles() {
// function calls in formatings work
assert_eq!(
format_args_f!("{x.borrow():?}").to_string(),
format!("{:?}", x.borrow())
format_args_f!("{blah(&x):?}").to_string(),
format!("{:?}", blah(&x))
);
// allows duplicate format args
@@ -30,3 +28,7 @@ fn formatting_compiles() {
format!("{x:?} {x:?}")
);
}
fn blah(hi: &(i32, i32)) -> String {
format_args_f!("{hi.0} {hi.1}").to_string()
}
+19
View File
@@ -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);
+3
View File
@@ -79,3 +79,6 @@ pub use usecallback::*;
mod usememo;
pub use usememo::*;
mod userootcontext;
pub use userootcontext::*;
+9
View File
@@ -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()))
})
}
+8 -2
View File
@@ -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());