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

This commit is contained in:
Greg Johnston 2023-09-03 20:07:20 -04:00 committed by GitHub
parent 4a43983f4e
commit 2ca24883ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 19 additions and 14 deletions

View file

@ -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,
};
@ -93,6 +95,9 @@ 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
@ -100,7 +105,7 @@ where
#[cfg(any(feature = "csr", feature = "hydrate"))]
{
if context.ready() {
if ready.get() {
children_rendered
} else {
fallback.get_untracked()

View file

@ -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 {

View file

@ -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};
@ -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))
}
}

View file

@ -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 {
@ -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);

View file

@ -451,8 +451,7 @@ 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 {
@ -460,7 +459,7 @@ fn root_route(
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);