Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: memoize Suspense readiness to avoid rerendering children/fallback #1642

Merged
merged 1 commit into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion leptos/src/suspense_component.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use leptos_dom::{DynChild, HydrationCtx, IntoView};
use leptos_macro::component;
#[cfg(any(feature = "csr", feature = "hydrate"))]
use leptos_reactive::SignalGet;
use leptos_reactive::{
create_memo, provide_context, SignalGetUntracked, SuspenseContext,
};
Expand Down Expand Up @@ -93,14 +95,17 @@ where

let current_id = HydrationCtx::next_component();

#[cfg(any(feature = "csr", feature = "hydrate"))]
let ready = context.ready();

let child = DynChild::new({
move || {
// pull lazy memo before checking if context is ready
let children_rendered = children.get_untracked();

#[cfg(any(feature = "csr", feature = "hydrate"))]
{
if context.ready() {
if ready.get() {
children_rendered
} else {
fallback.get_untracked()
Expand Down
4 changes: 3 additions & 1 deletion leptos/src/transition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ where
cfg!(feature = "csr") && first_run.get();
let is_first_run =
is_first_run(first_run, &suspense_context);
first_run.set(false);
if was_first_run {
first_run.set(false)
}

if let Some(prev_children) = &*prev_child.borrow() {
if is_first_run || was_first_run {
Expand Down
13 changes: 6 additions & 7 deletions leptos_reactive/src/suspense.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Types that handle asynchronous data loading via `<Suspense/>`.

use crate::{
create_isomorphic_effect, create_rw_signal, create_signal, oco::Oco,
queue_microtask, signal::SignalGet, store_value, ReadSignal, RwSignal,
SignalSet, SignalUpdate, StoredValue, WriteSignal,
create_isomorphic_effect, create_memo, create_rw_signal, create_signal,
oco::Oco, queue_microtask, signal::SignalGet, store_value, Memo,
ReadSignal, RwSignal, SignalSet, SignalUpdate, StoredValue, WriteSignal,
};
use futures::Future;
use std::{cell::RefCell, collections::VecDeque, pin::Pin, rc::Rc};
Expand Down Expand Up @@ -154,10 +154,9 @@ impl SuspenseContext {
}

/// Tests whether all of the pending resources have resolved.
pub fn ready(&self) -> bool {
self.pending_resources
.try_with(|n| *n == 0)
.unwrap_or(false)
pub fn ready(&self) -> Memo<bool> {
let pending = self.pending_resources;
create_memo(move |_| pending.try_with(|n| *n == 0).unwrap_or(false))
}
}

Expand Down
4 changes: 2 additions & 2 deletions router/src/components/outlet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ pub fn Outlet() -> impl IntoView {
move |prev| {
let outlet = outlet.get();
let is_fallback =
!global_suspense.with_inner(SuspenseContext::ready);
!global_suspense.with_inner(|c| c.ready().get());
if prev.is_none() {
set_current_view.set(outlet);
} else if !is_fallback {
Expand All @@ -81,7 +81,7 @@ pub fn Outlet() -> impl IntoView {
move || {
let is_fallback = untrack(move || {
!global_suspense
.with_inner(SuspenseContext::ready)
.with_inner(|c| c.ready().get())
});
if !is_fallback {
set_current_view.set(outlet);
Expand Down
5 changes: 2 additions & 3 deletions router/src/components/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,16 +451,15 @@ fn root_route(

create_effect(move |prev| {
let root = root_view.get();
let is_fallback =
!global_suspense.with_inner(SuspenseContext::ready);
let is_fallback = !global_suspense.with_inner(|c| c.ready().get());
if prev.is_none() {
set_current_view.set(root);
} else if !is_fallback {
queue_microtask({
let global_suspense = global_suspense.clone();
move || {
let is_fallback = untrack(move || {
!global_suspense.with_inner(SuspenseContext::ready)
!global_suspense.with_inner(|c| c.ready().get())
});
if !is_fallback {
set_current_view.set(root);
Expand Down