From 940108f242bc387c151115e08fc84f0530a4531e Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 15 Jan 2024 13:23:35 -0600 Subject: [PATCH] fix hydration --- packages/core/src/lib.rs | 8 ++--- packages/core/src/nodes.rs | 41 +++++++++++++++++++++++++ packages/core/src/runtime.rs | 6 ++-- packages/ssr/src/eval.rs | 6 ++-- packages/web/Cargo.toml | 2 +- packages/web/src/rehydrate.rs | 56 +++++++++++++++++++---------------- 6 files changed, 83 insertions(+), 36 deletions(-) diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 6f8016add..f9c207200 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -75,8 +75,8 @@ pub use crate::innerlude::{ fc_to_builder, generation, schedule_update, schedule_update_any, use_hook, vdom_is_rendering, AnyValue, Attribute, AttributeValue, CapturedError, Component, DynamicNode, Element, ElementId, Event, Fragment, HasAttributes, IntoDynNode, Mutation, Mutations, NoOpMutations, Properties, - RenderReturn, ScopeId, Task, Template, TemplateAttribute, TemplateNode, VComponent, VNode, - VNodeInner, VPlaceholder, VText, VirtualDom, WriteMutations, + RenderReturn, ScopeId, ScopeState, Task, Template, TemplateAttribute, TemplateNode, VComponent, + VNode, VNodeInner, VPlaceholder, VText, VirtualDom, WriteMutations, }; /// The purpose of this module is to alleviate imports of many common types @@ -89,7 +89,7 @@ pub mod prelude { push_future, remove_future, schedule_update, schedule_update_any, spawn, spawn_forever, suspend, use_error_boundary, use_hook, AnyValue, Attribute, Component, Element, ErrorBoundary, Event, EventHandler, Fragment, HasAttributes, IntoAttributeValue, - IntoDynNode, Properties, Runtime, RuntimeGuard, ScopeId, Task, Template, TemplateAttribute, - TemplateNode, Throw, VNode, VNodeInner, VirtualDom, + IntoDynNode, Properties, Runtime, RuntimeGuard, ScopeId, ScopeState, Task, Template, + TemplateAttribute, TemplateNode, Throw, VNode, VNodeInner, VirtualDom, }; } diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index f53db1f97..15abb552e 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -234,6 +234,47 @@ impl VNode { } } } + + /// Get the mounted id for a dynamic node index + pub fn mounted_dynamic_node( + &self, + dynamic_node_idx: usize, + dom: &VirtualDom, + ) -> Option { + let mount = self.mount.get().as_usize()?; + + match &self.dynamic_nodes[dynamic_node_idx] { + DynamicNode::Text(_) | DynamicNode::Placeholder(_) => dom + .mounts + .get(mount)? + .mounted_dynamic_nodes + .get(dynamic_node_idx) + .map(|id| ElementId(*id)), + _ => None, + } + } + + /// Get the mounted id for a root node index + pub fn mounted_root(&self, root_idx: usize, dom: &VirtualDom) -> Option { + let mount = self.mount.get().as_usize()?; + + dom.mounts.get(mount)?.root_ids.get(root_idx).copied() + } + + /// Get the mounted id for a dynamic attribute index + pub fn mounted_dynamic_attribute( + &self, + dynamic_attribute_idx: usize, + dom: &VirtualDom, + ) -> Option { + let mount = self.mount.get().as_usize()?; + + dom.mounts + .get(mount)? + .mounted_attributes + .get(dynamic_attribute_idx) + .copied() + } } /// A static layout of a UI tree that describes a set of dynamic and static nodes. diff --git a/packages/core/src/runtime.rs b/packages/core/src/runtime.rs index 699c9e6b3..69d83c6fc 100644 --- a/packages/core/src/runtime.rs +++ b/packages/core/src/runtime.rs @@ -147,13 +147,13 @@ impl Runtime { /// render! { div {} } /// } /// ``` -pub struct RuntimeGuard(Rc); +pub struct RuntimeGuard(()); impl RuntimeGuard { /// Create a new runtime guard that sets the current Dioxus runtime. The runtime will be reset when the guard is dropped pub fn new(runtime: Rc) -> Self { - push_runtime(runtime.clone()); - Self(runtime) + push_runtime(runtime); + Self(()) } /// Run a function with a given runtime and scope in context diff --git a/packages/ssr/src/eval.rs b/packages/ssr/src/eval.rs index b8d50986b..8b5d05b50 100644 --- a/packages/ssr/src/eval.rs +++ b/packages/ssr/src/eval.rs @@ -12,8 +12,8 @@ pub fn init_eval() { /// Reprents the ssr-target's provider of evaluators. pub struct SSREvalProvider; impl EvalProvider for SSREvalProvider { - fn new_evaluator(&self, _: String) -> Result, EvalError> { - Ok(Rc::new(SSREvaluator) as Rc) + fn new_evaluator(&self, _: String) -> Result, EvalError> { + Ok(Box::new(SSREvaluator) as Box) } } @@ -35,7 +35,7 @@ impl Evaluator for SSREvaluator { } /// Gets an UnboundedReceiver to receive messages from the evaluated JavaScript. - async fn recv(&self) -> Result { + async fn recv(&mut self) -> Result { std::future::pending::<()>().await; unreachable!() } diff --git a/packages/web/Cargo.toml b/packages/web/Cargo.toml index 4d61aa246..2486acbf8 100644 --- a/packages/web/Cargo.toml +++ b/packages/web/Cargo.toml @@ -75,7 +75,7 @@ eval = [ [dev-dependencies] dioxus = { workspace = true } wasm-bindgen-test = "0.3.29" -dioxus-ssr = { workspace = true} +dioxus-ssr = { workspace = true, default-features = false } gloo-timers = "0.2.3" gloo-dialogs = "0.1.1" dioxus-web = { path = ".", features = ["hydrate"] } diff --git a/packages/web/src/rehydrate.rs b/packages/web/src/rehydrate.rs index e50da9e2b..9ed427cfa 100644 --- a/packages/web/src/rehydrate.rs +++ b/packages/web/src/rehydrate.rs @@ -36,10 +36,7 @@ impl WebsysDom { ids: &mut Vec, to_mount: &mut Vec, ) -> Result<(), RehydrationError> { - let vnode = match scope.root_node() { - dioxus_core::RenderReturn::Ready(ready) => ready, - _ => return Err(VNodeNotInitialized), - }; + let vnode = scope.root_node(); self.rehydrate_vnode(dom, vnode, ids, to_mount) } @@ -57,7 +54,7 @@ impl WebsysDom { root, ids, to_mount, - Some(*vnode.root_ids.borrow().get(i).ok_or(VNodeNotInitialized)?), + Some(vnode.mounted_root(i, dom).ok_or(VNodeNotInitialized)?), )?; } Ok(()) @@ -80,9 +77,11 @@ impl WebsysDom { let mut mounted_id = root_id; for attr in *attrs { if let dioxus_core::TemplateAttribute::Dynamic { id } = attr { - let attribute = &vnode.dynamic_attrs[*id]; - let id = attribute.mounted_element(); - attribute.attribute_type().for_each(|attribute| { + let attributes = &*vnode.dynamic_attrs[*id]; + let id = vnode + .mounted_dynamic_attribute(*id, dom) + .ok_or(VNodeNotInitialized)?; + for attribute in attributes { let value = &attribute.value; mounted_id = Some(id); if let AttributeValue::Listener(_) = value { @@ -90,7 +89,7 @@ impl WebsysDom { to_mount.push(id); } } - }); + } } } if let Some(id) = mounted_id { @@ -102,9 +101,15 @@ impl WebsysDom { } } } - TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => { - self.rehydrate_dynamic_node(dom, &vnode.dynamic_nodes[*id], ids, to_mount)?; - } + TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => self + .rehydrate_dynamic_node( + dom, + &vnode.dynamic_nodes[*id], + *id, + vnode, + ids, + to_mount, + )?, _ => {} } Ok(()) @@ -114,28 +119,29 @@ impl WebsysDom { &mut self, dom: &VirtualDom, dynamic: &DynamicNode, + dynamic_node_index: usize, + vnode: &VNode, ids: &mut Vec, to_mount: &mut Vec, ) -> Result<(), RehydrationError> { tracing::trace!("rehydrate dynamic node: {:?}", dynamic); match dynamic { - dioxus_core::DynamicNode::Text(text) => { - ids.push(text.mounted_element().ok_or(VNodeNotInitialized)?.0 as u32); - } - dioxus_core::DynamicNode::Placeholder(placeholder) => { - ids.push(placeholder.mounted_element().ok_or(VNodeNotInitialized)?.0 as u32); + dioxus_core::DynamicNode::Text(_) | dioxus_core::DynamicNode::Placeholder(_) => { + ids.push( + vnode + .mounted_dynamic_node(dynamic_node_index, dom) + .ok_or(VNodeNotInitialized)? + .0 as u32, + ); } dioxus_core::DynamicNode::Component(comp) => { - let scope = comp.mounted_scope().ok_or(VNodeNotInitialized)?; - self.rehydrate_scope( - dom.get_scope(scope).ok_or(VNodeNotInitialized)?, - dom, - ids, - to_mount, - )?; + let scope = comp + .mounted_scope(dynamic_node_index, vnode, dom) + .ok_or(VNodeNotInitialized)?; + self.rehydrate_scope(scope, dom, ids, to_mount)?; } dioxus_core::DynamicNode::Fragment(fragment) => { - for vnode in *fragment { + for vnode in fragment { self.rehydrate_vnode(dom, vnode, ids, to_mount)?; } }