Fixes for <Suspense/> hydration

This commit is contained in:
Greg Johnston
2022-12-19 22:45:00 -05:00
parent 065d6b3c19
commit 79712ac4ef
2 changed files with 74 additions and 35 deletions

View File

@@ -93,19 +93,16 @@ where
use leptos_dom::DynChild;
Component::new("Suspense", move |cx| {
let cached_id = HydrationCtx::peek();
let mut cached_id = HydrationCtx::peek();
let mut id_to_replace = cached_id.clone();
id_to_replace.offset += 0;
DynChild::new(move || {
let mut id_to_replace = cached_id.clone();
id_to_replace.offset += 2;
if context.ready() {
HydrationCtx::continue_from(id_to_replace);
if context.ready() {
child(cx).into_view(cx)
} else {
fallback().into_view(cx)
}
})
child(cx).into_view(cx)
} else {
fallback().into_view(cx)
}
})
}
@@ -125,32 +122,37 @@ where
let orig_child = Rc::clone(&orig_child);
Component::new("Suspense", move |cx| {
DynChild::new(move || {
let current_id = HydrationCtx::peek();
let current_id = HydrationCtx::peek();
// run the child; we'll probably throw this away, but it will register resource reads
let child = orig_child(cx).into_view(cx);
// run the child; we'll probably throw this away, but it will register resource reads
let child = orig_child(cx).into_view(cx);
let initial = {
// no resources were read under this, so just return the child
if context.pending_resources.get() == 0 {
child.clone()
}
// show the fallback, but also prepare to stream HTML
else {
let orig_child = Rc::clone(&orig_child);
cx.register_suspense(context, &current_id.to_string(), move || {
let initial = {
// no resources were read under this, so just return the child
if context.pending_resources.get() == 0 {
child.clone()
}
// show the fallback, but also prepare to stream HTML
else {
let orig_child = Rc::clone(&orig_child);
cx.register_suspense(context, &current_id.to_string(), {
let current_id = current_id.clone();
move || {
HydrationCtx::continue_from(current_id);
orig_child(cx)
.into_view(cx)
.render_to_string(cx)
.to_string()
});
// return the fallback for now, wrapped in fragment identifer
fallback().into_view(cx)
}
};
initial
})
}
});
// return the fallback for now, wrapped in fragment identifer
fallback().into_view(cx)
}
};
HydrationCtx::continue_from(current_id);
initial
})
}

View File

@@ -4,8 +4,8 @@ use std::{
future::Future,
pin::Pin,
};
use cfg_if::cfg_if;
#[derive(Default)]
pub struct SharedContext {
pub events: Vec<()>,
pub pending_resources: HashSet<ResourceId>,
@@ -29,6 +29,43 @@ impl PartialEq for SharedContext {
impl Eq for SharedContext {}
impl SharedContext {
impl Default for SharedContext {
}
fn default() -> Self {
cfg_if! {
if #[cfg(feature = "hydrate")] {
let pending_resources = js_sys::Reflect::get(
&web_sys::window().unwrap(),
&wasm_bindgen::JsValue::from_str("__LEPTOS_PENDING_RESOURCES"),
);
let pending_resources: HashSet<ResourceId> = pending_resources
.map_err(|_| ())
.and_then(|pr| serde_wasm_bindgen::from_value(pr).map_err(|_| ()))
.unwrap_or_default();
let resolved_resources = js_sys::Reflect::get(
&web_sys::window().unwrap(),
&wasm_bindgen::JsValue::from_str("__LEPTOS_RESOLVED_RESOURCES"),
)
.unwrap_or(wasm_bindgen::JsValue::NULL);
let resolved_resources =
serde_wasm_bindgen::from_value(resolved_resources).unwrap_or_default();
Self {
events: Default::default(),
pending_resources,
resolved_resources,
pending_fragments: Default::default(),
}
} else {
Self {
events: Default::default(),
pending_resources: Default::default(),
resolved_resources: Default::default(),
pending_fragments: Default::default(),
}
}
}
}
}