added `HydrationCtx` helpers and fixed a couple bugs with the hydration example

This commit is contained in:
Jose Quesada 2022-12-15 10:04:44 -06:00
parent 416e1a617b
commit 9eadac9f2c
6 changed files with 54 additions and 16 deletions

View File

@ -1,3 +1,4 @@
use leptos_dom::HydrationCtx;
use leptos_dom::{Fragment, IntoView};
use leptos_reactive::{provide_context, Scope, SuspenseContext};
use typed_builder::TypedBuilder;
@ -88,10 +89,28 @@ where
F: Fn() -> E + 'static,
E: IntoView,
{
use std::cell::RefCell;
use leptos_dom::DynChild;
let cached_id = RefCell::new(None);
DynChild::new(move || {
let mut cached_id_borrow = cached_id.borrow_mut();
let first_run = if cached_id_borrow.is_none() {
*cached_id_borrow = Some(HydrationCtx::peak());
true
} else {
false
};
if context.ready() {
if let Some(id) = *cached_id_borrow {
HydrationCtx::continue_from(id);
}
child(cx).into_view(cx)
} else {
fallback().into_view(cx)
@ -124,14 +143,14 @@ where
else {
let key = cx.current_fragment_key();
cx.register_suspense(context, &key, move || {
orig_child(cx).into_view(cx).render_to_string(cx).to_string()
orig_child(cx)
.into_view(cx)
.render_to_string(cx)
.to_string()
});
// return the fallback for now, wrapped in fragment identifer
div(cx)
.id(key.to_string())
.child(fallback)
.into_view(cx)
div(cx).id(key.to_string()).child(fallback).into_view(cx)
}
};
initial

View File

@ -11,6 +11,7 @@ leptos = { path = "../../../leptos", default-features = false }
actix-web = { version = "4", optional = true }
actix-files = { version = "0.6", optional = true }
wasm-bindgen = { version = "0.2", optional = true}
gloo = { version = "0.8", optional = true }
console_error_panic_hook = "0.1.7"
cfg-if = "1.0.0"
gloo-timers = { version = "0.2", features = ["futures"] }
@ -19,6 +20,6 @@ futures = "0.3"
[features]
default = ["ssr"]
ssr = ["leptos/ssr", "dep:actix-files", "dep:actix-web"]
hydrate = ["leptos/hydrate", "dep:wasm-bindgen"]
hydrate = ["leptos/hydrate", "dep:wasm-bindgen", "dep:gloo"]
[workspace]

View File

@ -11,15 +11,14 @@ pub fn App(cx: Scope) -> impl IntoView {
if cfg!(feature = "ssr") {
let (tx, rx) = futures::channel::oneshot::channel();
spawn_local(async {
std::thread::sleep(std::time::Duration::from_millis(500));
std::thread::sleep(std::time::Duration::from_secs(10));
tx.send(());
});
rx.await;
} else {
}
()
}
},
);
view! { cx,
@ -35,11 +34,13 @@ pub fn App(cx: Scope) -> impl IntoView {
}
#[component]
pub fn ComponentA(cx: Scope, children: Box<dyn Fn() -> Vec<View>>) -> impl IntoView {
pub fn ComponentA(
cx: Scope,
children: Box<dyn Fn() -> Vec<View>>,
) -> impl IntoView {
let (value, set_value) = create_signal(cx, "Hello?".to_string());
let (counter, set_counter) = create_signal(cx, 0);
// Test to make sure hydration isn't broken by
// something like this
let _ = [div(cx)].into_view(cx);
@ -66,6 +67,8 @@ use wasm_bindgen::prelude::wasm_bindgen;
pub fn hydrate() {
console_error_panic_hook::set_once();
gloo::console::debug!("starting WASM");
leptos::mount_to_body(move |cx| {
view! { cx, <App/> }
});

View File

@ -1,8 +1,8 @@
use actix_files::Files;
use actix_web::*;
use futures::StreamExt;
use hydration_test::*;
use leptos::*;
use futures::StreamExt;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
@ -21,17 +21,19 @@ async fn main() -> std::io::Result<()> {
<link rel="modulepreload" href="{pkg_path}.js">
<link rel="preload" href="{pkg_path}_bg.wasm" as="fetch" type="application/wasm" crossorigin="">
<script type="module">import init, {{ hydrate }} from '{pkg_path}.js'; init('{pkg_path}_bg.wasm').then(hydrate);</script>
"#
</head>
<body>"#
);
let tail = "</body></html>";
HttpResponse::Ok().content_type("text/html").streaming(
futures::stream::once(async move { head.clone() })
.chain(render_to_stream(
.chain(render_to_stream(
|cx| view! { cx, <App/> }.into_view(cx),
))
.chain(futures::stream::once(async { tail.to_string() }))
.inspect(|html| println!("{html}"))
.map(|html| Ok(web::Bytes::from(html)) as Result<web::Bytes>),
)})
))

View File

@ -20,9 +20,15 @@ static mut IS_HYDRATING: LazyCell<bool> = LazyCell::new(|| {
#[thread_local]
static mut ID: usize = 0;
pub(crate) struct HydrationCtx;
/// Control and utility methods for hydration.
pub struct HydrationCtx;
impl HydrationCtx {
/// Get the next `id` without incrementing it.
pub fn peak() -> usize {
unsafe { ID }
}
pub(crate) fn id() -> usize {
unsafe {
let id = ID;
@ -44,6 +50,12 @@ impl HydrationCtx {
unsafe { ID = 0 };
}
/// Resums hydration from the provided `id`. Usefull for
/// `Suspense` and other fancy things.
pub fn continue_from(id: usize) {
unsafe { ID = id }
}
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
pub(crate) fn set_id(cx: Scope) {
/* let new_id = if let Some(id) = cx.get_hydration_key() {

View File

@ -19,12 +19,13 @@ mod node_ref;
mod ssr;
mod transparent;
use cfg_if::cfg_if;
pub use components::*;
pub use events::typed as ev;
pub use helpers::*;
pub use html::*;
use hydration::HydrationCtx;
pub use hydration::HydrationCtx;
pub use js_sys;
use leptos_reactive::Scope;
pub use logging::*;