Skip to content

Commit

Permalink
fix: #1742 part 2 (Suspense running children a second time => extra…
Browse files Browse the repository at this point in the history
… animations)
  • Loading branch information
gbj authored Sep 19, 2023
1 parent 1bd47f3 commit fafb6c0
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 18 deletions.
30 changes: 14 additions & 16 deletions leptos/src/suspense_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -75,16 +77,6 @@ where
let owner =
Owner::current().expect("<Suspense/> 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 |_| {
Expand All @@ -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()
}
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions leptos_reactive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down
34 changes: 34 additions & 0 deletions leptos_reactive/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,40 @@ where
}
}

/// Runs the given function as a child of the current Owner, once.
pub fn run_as_child<T>(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.
Expand Down

0 comments on commit fafb6c0

Please sign in to comment.