Browse Source

fix hydration

Evan Almloff 1 năm trước cách đây
mục cha
commit
940108f242

+ 4 - 4
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,
     };
 }

+ 41 - 0
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<ElementId> {
+        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<ElementId> {
+        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<ElementId> {
+        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.

+ 3 - 3
packages/core/src/runtime.rs

@@ -147,13 +147,13 @@ impl Runtime {
 ///     render! { div {} }
 /// }
 /// ```
-pub struct RuntimeGuard(Rc<Runtime>);
+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<Runtime>) -> Self {
-        push_runtime(runtime.clone());
-        Self(runtime)
+        push_runtime(runtime);
+        Self(())
     }
 
     /// Run a function with a given runtime and scope in context

+ 3 - 3
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<Rc<dyn Evaluator>, EvalError> {
-        Ok(Rc::new(SSREvaluator) as Rc<dyn Evaluator + 'static>)
+    fn new_evaluator(&self, _: String) -> Result<Box<dyn Evaluator>, EvalError> {
+        Ok(Box::new(SSREvaluator) as Box<dyn Evaluator + 'static>)
     }
 }
 
@@ -35,7 +35,7 @@ impl Evaluator for SSREvaluator {
     }
 
     /// Gets an UnboundedReceiver to receive messages from the evaluated JavaScript.
-    async fn recv(&self) -> Result<serde_json::Value, EvalError> {
+    async fn recv(&mut self) -> Result<serde_json::Value, EvalError> {
         std::future::pending::<()>().await;
         unreachable!()
     }

+ 1 - 1
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"] }

+ 31 - 25
packages/web/src/rehydrate.rs

@@ -36,10 +36,7 @@ impl WebsysDom {
         ids: &mut Vec<u32>,
         to_mount: &mut Vec<ElementId>,
     ) -> 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<u32>,
         to_mount: &mut Vec<ElementId>,
     ) -> 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)?;
                 }
             }