mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
perf: reduce overhead of hydration keys (#1122)
This commit is contained in:
parent
f3e544b003
commit
55266f2efd
12 changed files with 60 additions and 61 deletions
|
@ -36,7 +36,7 @@ pub fn Stories(cx: Scope) -> impl IntoView {
|
|||
);
|
||||
let (pending, set_pending) = create_signal(cx, false);
|
||||
|
||||
let hide_more_link = move || {
|
||||
let hide_more_link = move |cx| {
|
||||
pending()
|
||||
|| stories.read(cx).unwrap_or(None).unwrap_or_default().len() < 28
|
||||
};
|
||||
|
@ -66,16 +66,20 @@ pub fn Stories(cx: Scope) -> impl IntoView {
|
|||
}}
|
||||
</span>
|
||||
<span>"page " {page}</span>
|
||||
<span class="page-link"
|
||||
class:disabled=hide_more_link
|
||||
aria-hidden=hide_more_link
|
||||
<Transition
|
||||
fallback=move || view! { cx, <p>"Loading..."</p> }
|
||||
>
|
||||
<a href=move || format!("/{}?page={}", story_type(), page() + 1)
|
||||
aria-label="Next Page"
|
||||
<span class="page-link"
|
||||
class:disabled=move || hide_more_link(cx)
|
||||
aria-hidden=move || hide_more_link(cx)
|
||||
>
|
||||
"more >"
|
||||
</a>
|
||||
</span>
|
||||
<a href=move || format!("/{}?page={}", story_type(), page() + 1)
|
||||
aria-label="Next Page"
|
||||
>
|
||||
"more >"
|
||||
</a>
|
||||
</span>
|
||||
</Transition>
|
||||
</div>
|
||||
<main class="news-list">
|
||||
<div>
|
||||
|
|
|
@ -102,7 +102,7 @@ where
|
|||
|
||||
// run the child; we'll probably throw this away, but it will register resource reads
|
||||
let _child = orig_child(cx).into_view(cx);
|
||||
let after_original_child = HydrationCtx::id();
|
||||
let after_original_child = HydrationCtx::peek();
|
||||
|
||||
let initial = {
|
||||
// no resources were read under this, so just return the child
|
||||
|
@ -116,13 +116,13 @@ where
|
|||
// show the fallback, but also prepare to stream HTML
|
||||
else {
|
||||
let orig_child = Rc::clone(&orig_child);
|
||||
HydrationCtx::continue_from(current_id);
|
||||
|
||||
cx.register_suspense(
|
||||
context,
|
||||
¤t_id.to_string(),
|
||||
// out-of-order streaming
|
||||
{
|
||||
let current_id = current_id.clone();
|
||||
let orig_child = Rc::clone(&orig_child);
|
||||
move || {
|
||||
HydrationCtx::continue_from(current_id.clone());
|
||||
|
@ -136,7 +136,6 @@ where
|
|||
},
|
||||
// in-order streaming
|
||||
{
|
||||
let current_id = current_id.clone();
|
||||
move || {
|
||||
HydrationCtx::continue_from(current_id.clone());
|
||||
Fragment::lazy(Box::new(move || {
|
||||
|
@ -165,7 +164,8 @@ where
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
HydrationCtx::continue_from(current_id.clone());
|
||||
HydrationCtx::continue_from(current_id);
|
||||
HydrationCtx::next_component();
|
||||
|
||||
leptos_dom::View::Suspense(current_id, core_component)
|
||||
}
|
||||
|
|
|
@ -52,11 +52,11 @@ fn ssr_test_with_components() {
|
|||
};
|
||||
|
||||
assert!(rendered.into_view(cx).render_to_string(cx).contains(
|
||||
"<div id=\"_0-1-1\"><button id=\"_0-1-2\">-1</button><span \
|
||||
id=\"_0-1-3\">Value: \
|
||||
<!--hk=_0-1-4o|leptos-dyn-child-start-->1<!\
|
||||
--hk=_0-1-4c|leptos-dyn-child-end-->!</span><button \
|
||||
id=\"_0-1-5\">+1</button></div>"
|
||||
"<div id=\"_0-3\"><button id=\"_0-4\">-1</button><span \
|
||||
id=\"_0-5\">Value: \
|
||||
<!--hk=_0-6o|leptos-dyn-child-start-->1<!\
|
||||
--hk=_0-6c|leptos-dyn-child-end-->!</span><button \
|
||||
id=\"_0-7\">+1</button></div>"
|
||||
));
|
||||
});
|
||||
}
|
||||
|
@ -89,11 +89,11 @@ fn ssr_test_with_snake_case_components() {
|
|||
};
|
||||
|
||||
assert!(rendered.into_view(cx).render_to_string(cx).contains(
|
||||
"<div id=\"_0-1-1\"><button id=\"_0-1-2\">-1</button><span \
|
||||
id=\"_0-1-3\">Value: \
|
||||
<!--hk=_0-1-4o|leptos-dyn-child-start-->1<!\
|
||||
--hk=_0-1-4c|leptos-dyn-child-end-->!</span><button \
|
||||
id=\"_0-1-5\">+1</button></div>"
|
||||
"<div id=\"_0-3\"><button id=\"_0-4\">-1</button><span \
|
||||
id=\"_0-5\">Value: \
|
||||
<!--hk=_0-6o|leptos-dyn-child-start-->1<!\
|
||||
--hk=_0-6c|leptos-dyn-child-end-->!</span><button \
|
||||
id=\"_0-7\">+1</button></div>"
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ fn SecondaryNav(cx: Scope) -> impl IntoView {
|
|||
fn Nested(cx: Scope) -> impl IntoView {
|
||||
let one_second = create_resource(cx, || (), one_second_fn);
|
||||
let two_second = create_resource(cx, || (), two_second_fn);
|
||||
let (count, set_count) = create_signal(cx, 0);
|
||||
|
||||
view! { cx,
|
||||
<div>
|
||||
|
@ -125,7 +126,12 @@ fn Nested(cx: Scope) -> impl IntoView {
|
|||
<Suspense fallback=|| "Loading 2...">
|
||||
"Two Second: "
|
||||
{move || {
|
||||
two_second.read(cx).map(|_| "Loaded 2!")
|
||||
two_second.read(cx).map(|_| view! { cx,
|
||||
"Loaded 2!"
|
||||
<button on:click=move |_| set_count.update(|n| *n += 1)>
|
||||
{count}
|
||||
</button>
|
||||
})
|
||||
}}
|
||||
</Suspense>
|
||||
</Suspense>
|
||||
|
|
|
@ -242,7 +242,7 @@ where
|
|||
/// Creates a new component.
|
||||
pub fn new(name: impl Into<Cow<'static, str>>, f: F) -> Self {
|
||||
Self {
|
||||
id: HydrationCtx::next_component(),
|
||||
id: HydrationCtx::id(),
|
||||
name: name.into(),
|
||||
children_fn: f,
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ where
|
|||
E: Error + Send + Sync + 'static,
|
||||
{
|
||||
fn into_view(self, cx: leptos_reactive::Scope) -> crate::View {
|
||||
let id = ErrorKey(HydrationCtx::peek().previous.into());
|
||||
let id = ErrorKey(HydrationCtx::peek().id.to_string().into());
|
||||
let errors = use_context::<RwSignal<Errors>>(cx);
|
||||
match self {
|
||||
Ok(stuff) => {
|
||||
|
|
|
@ -47,7 +47,7 @@ impl From<View> for Fragment {
|
|||
|
||||
impl From<Fragment> for View {
|
||||
fn from(value: Fragment) -> Self {
|
||||
let mut frag = ComponentRepr::new_with_id("", value.id.clone());
|
||||
let mut frag = ComponentRepr::new_with_id("", value.id);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
|
|
|
@ -449,7 +449,7 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
|
|||
element: AnyElement {
|
||||
name: element.name(),
|
||||
is_void: element.is_void(),
|
||||
id: element.hydration_id().clone()
|
||||
id: *element.hydration_id()
|
||||
},
|
||||
#[cfg(debug_assertions)]
|
||||
view_marker
|
||||
|
@ -1072,7 +1072,7 @@ impl<El: ElementDescriptor> IntoView for HtmlElement<El> {
|
|||
..
|
||||
} = self;
|
||||
|
||||
let id = element.hydration_id().clone();
|
||||
let id = *element.hydration_id();
|
||||
|
||||
let mut element = Element::new(element);
|
||||
let children = children;
|
||||
|
@ -1116,7 +1116,7 @@ pub fn custom<El: ElementDescriptor>(cx: Scope, el: El) -> HtmlElement<Custom> {
|
|||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
element: el.as_ref().clone(),
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
id: el.hydration_id().clone(),
|
||||
id: *el.hydration_id(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -50,13 +50,13 @@ cfg_if! {
|
|||
|
||||
static IS_HYDRATING: RefCell<LazyCell<bool>> = RefCell::new(LazyCell::new(|| {
|
||||
#[cfg(debug_assertions)]
|
||||
return crate::document().get_element_by_id("_0-0-0").is_some()
|
||||
|| crate::document().get_element_by_id("_0-0-0o").is_some()
|
||||
|| HYDRATION_COMMENTS.with(|comments| comments.get("_0-0-0o").is_some());
|
||||
return crate::document().get_element_by_id("_0-1").is_some()
|
||||
|| crate::document().get_element_by_id("_0-1o").is_some()
|
||||
|| HYDRATION_COMMENTS.with(|comments| comments.get("_0-1o").is_some());
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
return crate::document().get_element_by_id("_0-0-0").is_some()
|
||||
|| HYDRATION_COMMENTS.with(|comments| comments.get("_0-0-0").is_some());
|
||||
return crate::document().get_element_by_id("_0-1").is_some()
|
||||
|| HYDRATION_COMMENTS.with(|comments| comments.get("_0-1").is_some());
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -67,26 +67,17 @@ cfg_if! {
|
|||
}
|
||||
|
||||
/// A stable identifier within the server-rendering or hydration process.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
|
||||
pub struct HydrationKey {
|
||||
/// The key of the previous component.
|
||||
pub previous: String,
|
||||
/// The element offset within the current component.
|
||||
pub offset: usize,
|
||||
/// ID of the current key.
|
||||
pub id: usize,
|
||||
/// ID of the current fragment.
|
||||
pub fragment: usize,
|
||||
}
|
||||
|
||||
impl Display for HydrationKey {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}{}", self.previous, self.offset)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HydrationKey {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
previous: "0-".to_string(),
|
||||
offset: 0,
|
||||
}
|
||||
write!(f, "{}-{}", self.fragment, self.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,15 +89,15 @@ pub struct HydrationCtx;
|
|||
impl HydrationCtx {
|
||||
/// Get the next `id` without incrementing it.
|
||||
pub fn peek() -> HydrationKey {
|
||||
ID.with(|id| id.borrow().clone())
|
||||
ID.with(|id| *id.borrow())
|
||||
}
|
||||
|
||||
/// Increments the current hydration `id` and returns it
|
||||
pub fn id() -> HydrationKey {
|
||||
ID.with(|id| {
|
||||
let mut id = id.borrow_mut();
|
||||
id.offset = id.offset.wrapping_add(1);
|
||||
id.clone()
|
||||
id.id = id.id.wrapping_add(1);
|
||||
*id
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -114,11 +105,9 @@ impl HydrationCtx {
|
|||
pub fn next_component() -> HydrationKey {
|
||||
ID.with(|id| {
|
||||
let mut id = id.borrow_mut();
|
||||
let offset = id.offset;
|
||||
id.previous.push_str(&offset.to_string());
|
||||
id.previous.push('-');
|
||||
id.offset = 0;
|
||||
id.clone()
|
||||
id.fragment = id.fragment.wrapping_add(1);
|
||||
id.id = 0;
|
||||
*id
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -376,7 +376,7 @@ impl Element {
|
|||
is_void: el.is_void(),
|
||||
attrs: Default::default(),
|
||||
children: Default::default(),
|
||||
id: el.hydration_id().clone(),
|
||||
id: *el.hydration_id(),
|
||||
#[cfg(debug_assertions)]
|
||||
view_marker: None
|
||||
}
|
||||
|
|
|
@ -393,7 +393,7 @@ impl View {
|
|||
View::CoreComponent(node) => {
|
||||
let (id, name, wrap, content) = match node {
|
||||
CoreComponent::Unit(u) => (
|
||||
u.id.clone(),
|
||||
u.id,
|
||||
"",
|
||||
false,
|
||||
Box::new(move || {
|
||||
|
|
|
@ -374,7 +374,7 @@ impl View {
|
|||
View::CoreComponent(node) => {
|
||||
let (id, name, wrap, content) = match node {
|
||||
CoreComponent::Unit(u) => (
|
||||
u.id.clone(),
|
||||
u.id,
|
||||
"",
|
||||
false,
|
||||
Box::new(move |chunks: &mut VecDeque<StreamChunk>| {
|
||||
|
|
Loading…
Reference in a new issue