diff --git a/leptos/src/suspense_component.rs b/leptos/src/suspense_component.rs
index e4720dbe09..ec18d46172 100644
--- a/leptos/src/suspense_component.rs
+++ b/leptos/src/suspense_component.rs
@@ -2,8 +2,10 @@ use leptos_dom::{DynChild, HydrationCtx, IntoView};
use leptos_macro::component;
#[cfg(any(feature = "csr", feature = "hydrate"))]
use leptos_reactive::SignalGet;
+#[allow(unused)]
use leptos_reactive::{
- create_memo, provide_context, SignalGetUntracked, SuspenseContext,
+ create_memo, provide_context, run_as_child, SignalGetUntracked,
+ SuspenseContext,
};
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
use leptos_reactive::{with_owner, Owner, SharedContext};
@@ -75,16 +77,6 @@ where
let owner =
Owner::current().expect(" created with no reactive owner");
- // provide this SuspenseContext to any resources below it
- // run in a memo so the children are children of this parent
- let children = create_memo({
- let orig_children = Rc::clone(&orig_children);
- move |_| {
- provide_context(context);
- orig_children().into_view()
- }
- });
-
// likewise for the fallback
let fallback = create_memo({
move |_| {
@@ -100,13 +92,20 @@ where
let child = DynChild::new({
move || {
- // pull lazy memo before checking if context is ready
- let children_rendered = children.get_untracked();
+ // provide this SuspenseContext to any resources below it
+ // run in a memo so the children are children of this parent
+ let children = run_as_child({
+ let orig_children = Rc::clone(&orig_children);
+ move || {
+ provide_context(context);
+ orig_children().into_view()
+ }
+ });
#[cfg(any(feature = "csr", feature = "hydrate"))]
{
if ready.get() {
- children_rendered
+ children
} else {
fallback.get_untracked()
}
@@ -123,8 +122,7 @@ where
if context.pending_resources.get() == 0 {
with_owner(owner, move || {
//HydrationCtx::continue_from(current_id);
- DynChild::new(move || children_rendered.clone())
- .into_view()
+ DynChild::new(move || children.clone()).into_view()
})
}
// show the fallback, but also prepare to stream HTML
diff --git a/leptos_reactive/src/lib.rs b/leptos_reactive/src/lib.rs
index 7367ab737c..a7dc6bbf3b 100644
--- a/leptos_reactive/src/lib.rs
+++ b/leptos_reactive/src/lib.rs
@@ -114,8 +114,8 @@ pub use resource::*;
use runtime::*;
pub use runtime::{
as_child_of_current_owner, batch, create_runtime, current_runtime,
- on_cleanup, set_current_runtime, untrack, untrack_with_diagnostics,
- with_current_owner, with_owner, Owner, RuntimeId,
+ on_cleanup, run_as_child, set_current_runtime, untrack,
+ untrack_with_diagnostics, with_current_owner, with_owner, Owner, RuntimeId,
};
pub use selector::*;
pub use serialization::*;
diff --git a/leptos_reactive/src/runtime.rs b/leptos_reactive/src/runtime.rs
index fcb5f4eab6..6edee94883 100644
--- a/leptos_reactive/src/runtime.rs
+++ b/leptos_reactive/src/runtime.rs
@@ -680,6 +680,40 @@ where
}
}
+/// Runs the given function as a child of the current Owner, once.
+pub fn run_as_child(f: impl FnOnce() -> T + 'static) -> T {
+ let owner = with_runtime(|runtime| runtime.owner.get())
+ .expect("runtime should be alive when created");
+ let (value, disposer) = with_runtime(|runtime| {
+ let prev_observer = runtime.observer.take();
+ let prev_owner = runtime.owner.take();
+
+ runtime.owner.set(owner);
+ runtime.observer.set(owner);
+
+ let id = runtime.nodes.borrow_mut().insert(ReactiveNode {
+ value: None,
+ state: ReactiveNodeState::Clean,
+ node_type: ReactiveNodeType::Trigger,
+ });
+ runtime.push_scope_property(ScopeProperty::Trigger(id));
+ let disposer = Disposer(id);
+
+ runtime.owner.set(Some(id));
+ runtime.observer.set(Some(id));
+
+ let v = f();
+
+ runtime.observer.set(prev_observer);
+ runtime.owner.set(prev_owner);
+
+ (v, disposer)
+ })
+ .expect("runtime should be alive when run");
+ on_cleanup(move || drop(disposer));
+ value
+}
+
/// Wraps the given function so that, whenever it is called, it is run
/// in the reactive scope of whatever the reactive owner was when it was
/// created.