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:
6 files changed
+46
-10
No files matched your search
+1
-4
@@ -1,5 +1,4 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_signals::{use_init_signal_rt, use_signal};
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -7,9 +6,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
use_init_signal_rt(cx);
|
let mut count = dioxus_signals::use_signal(cx, || 0);
|
||||||
|
|
||||||
let mut count = use_signal(cx, || 0);
|
|
||||||
|
|
||||||
use_future!(cx, || async move {
|
use_future!(cx, || async move {
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
use std::borrow::Borrow;
|
|
||||||
|
|
||||||
use dioxus_core_macro::*;
|
use dioxus_core_macro::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -20,8 +18,8 @@ fn formatting_compiles() {
|
|||||||
|
|
||||||
// function calls in formatings work
|
// function calls in formatings work
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format_args_f!("{x.borrow():?}").to_string(),
|
format_args_f!("{blah(&x):?}").to_string(),
|
||||||
format!("{:?}", x.borrow())
|
format!("{:?}", blah(&x))
|
||||||
);
|
);
|
||||||
|
|
||||||
// allows duplicate format args
|
// allows duplicate format args
|
||||||
@@ -30,3 +28,7 @@ fn formatting_compiles() {
|
|||||||
format!("{x:?} {x:?}")
|
format!("{x:?} {x:?}")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn blah(hi: &(i32, i32)) -> String {
|
||||||
|
format_args_f!("{hi.0} {hi.1}").to_string()
|
||||||
|
}
|
||||||
@@ -418,6 +418,25 @@ impl<'src> ScopeState {
|
|||||||
value
|
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.
|
/// 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 {
|
pub fn push_future(&self, fut: impl Future<Output = ()> + 'static) -> TaskId {
|
||||||
let id = self.tasks.spawn(self.id, fut);
|
let id = self.tasks.spawn(self.id, fut);
|
||||||
|
|||||||
@@ -79,3 +79,6 @@ pub use usecallback::*;
|
|||||||
|
|
||||||
mod usememo;
|
mod usememo;
|
||||||
pub use 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;
|
use dioxus_core::ScopeState;
|
||||||
pub use rt::*;
|
pub use rt::*;
|
||||||
|
|
||||||
|
use crate::rt::claim_rt;
|
||||||
|
|
||||||
pub fn use_init_signal_rt(cx: &ScopeState) {
|
pub fn use_init_signal_rt(cx: &ScopeState) {
|
||||||
cx.use_hook(|| {
|
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);
|
cx.provide_context(rt);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_signal<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal<T> {
|
pub fn use_signal<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal<T> {
|
||||||
cx.use_hook(|| {
|
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());
|
let id = rt.init(f());
|
||||||
rt.subscribe(id, cx.scope_id());
|
rt.subscribe(id, cx.scope_id());
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user