Browse Source

fix mounted information

Evan Almloff 1 year ago
parent
commit
b43dfb1f67

+ 0 - 9
packages/core/src/arena.rs

@@ -23,11 +23,6 @@ impl Default for MountId {
 }
 
 impl MountId {
-    pub(crate) fn new(id: usize) -> Self {
-        debug_assert_ne!(id, usize::MAX);
-        Self(id)
-    }
-
     pub(crate) fn as_usize(self) -> Option<usize> {
         if self.0 == usize::MAX {
             None
@@ -35,10 +30,6 @@ impl MountId {
             Some(self.0)
         }
     }
-
-    pub(crate) fn is_none(self) -> bool {
-        self.0 == usize::MAX
-    }
 }
 
 #[derive(Debug, Clone, Copy)]

+ 7 - 6
packages/core/src/diff/component.rs

@@ -22,9 +22,6 @@ impl VirtualDom {
         let new = &new_nodes;
         let old = scope_state.last_rendered_node.take().unwrap();
 
-        use RenderReturn::{Aborted, Ready};
-
-        let (Ready(old) | Aborted(old), Ready(new) | Aborted(new)) = (&old, new);
         old.diff_node(new, self, to);
 
         let scope_state = &mut self.scopes[scope.0];
@@ -40,11 +37,17 @@ impl VirtualDom {
         &mut self,
         to: &mut impl WriteMutations,
         scope: ScopeId,
-        new_node: &VNode,
+        new_node: &RenderReturn,
         parent: Option<ElementRef>,
     ) -> usize {
         self.runtime.scope_stack.borrow_mut().push(scope);
+
+        // Create the node
         let nodes = new_node.create(self, to, parent);
+
+        // Then set the new node as the last rendered node
+        self.scopes[scope.0].last_rendered_node = Some(new_node.clone());
+
         self.runtime.scope_stack.borrow_mut().pop();
         nodes
     }
@@ -134,8 +137,6 @@ impl VNode {
 
         let new = dom.run_scope(scope);
 
-        dom.scopes[scope.0].last_rendered_node = Some(new.clone());
-
         dom.create_scope(to, scope, &new, parent)
     }
 }

+ 23 - 13
packages/core/src/diff/node.rs

@@ -20,6 +20,9 @@ impl VNode {
         dom: &mut VirtualDom,
         to: &mut impl WriteMutations,
     ) {
+        // The node we are diffing from should always be mounted
+        debug_assert!(dom.mounts.get(self.mount.get().0).is_some());
+
         // If hot reloading is enabled, we need to make sure we're using the latest template
         #[cfg(debug_assertions)]
         {
@@ -44,7 +47,7 @@ impl VNode {
         let mount = &mut dom.mounts[mount_id.0];
 
         // Update the reference to the node for bubbling events
-        mount.node = new.clone_with_parent();
+        mount.node = new.clone_mounted();
 
         // If the templates are the same, we don't need to do anything, except copy over the mount information
         if self == new {
@@ -216,6 +219,8 @@ impl VNode {
 
         // Remove the mount information
         dom.mounts.remove(mount.0);
+
+        tracing::trace!(?self, "removed node");
     }
 
     fn reclaim_roots(
@@ -419,6 +424,19 @@ impl VNode {
         // Just in case, let's create the template using instructions anyways
         dom.register_template(to, template);
 
+        // Initialize the mount information for this template
+        let entry = dom.mounts.vacant_entry();
+        let mount = MountId(entry.key());
+        self.mount.set(mount);
+        tracing::info!(?self, ?mount, "creating template");
+        entry.insert(VNodeMount {
+            node: self.clone_mounted(),
+            parent,
+            root_ids: vec![ElementId(0); template.roots.len()].into_boxed_slice(),
+            mounted_attributes: vec![ElementId(0); template.attr_paths.len()].into_boxed_slice(),
+            mounted_dynamic_nodes: vec![0; template.node_paths.len()].into_boxed_slice(),
+        });
+
         // Walk the roots, creating nodes and assigning IDs
         // nodes in an iterator of ((dynamic_node_index, sorted_index), path)
         // todo: adjust dynamic nodes to be in the order of roots and then leaves (ie BFS)
@@ -451,18 +469,6 @@ impl VNode {
             )
         };
 
-        // Initialize the mount information for this template
-        let entry = dom.mounts.vacant_entry();
-        let mount = MountId(entry.key());
-        self.mount.set(mount);
-        entry.insert(VNodeMount {
-            node: self.clone_with_parent(),
-            parent,
-            root_ids: vec![ElementId(0); template.roots.len()].into_boxed_slice(),
-            mounted_attributes: vec![ElementId(0); template.attr_paths.len()].into_boxed_slice(),
-            mounted_dynamic_nodes: vec![0; template.node_paths.len()].into_boxed_slice(),
-        });
-
         template
             .roots
             .iter()
@@ -672,6 +678,10 @@ impl VNode {
             AttributeValue::Listener(_) => {
                 // If this is a listener, we need to create an element reference for it so that when we receive an event, we can find the element
                 let path = &self.template.get().attr_paths[idx];
+
+                // The mount information should always be in the VDOM at this point
+                debug_assert!(dom.mounts.get(mount.0).is_some());
+
                 let element_ref = ElementRef {
                     path: ElementPath { path },
                     mount,

+ 1 - 2
packages/core/src/lib.rs

@@ -29,7 +29,6 @@ pub(crate) mod innerlude {
     pub use crate::fragment::*;
     pub use crate::global_context::*;
     pub use crate::mutations::*;
-    pub use crate::nodes::RenderReturn;
     pub use crate::nodes::*;
     pub use crate::properties::*;
     pub use crate::runtime::{Runtime, RuntimeGuard};
@@ -75,7 +74,7 @@ pub(crate) mod innerlude {
 pub use crate::innerlude::{
     fc_to_builder, generation, once, schedule_update, schedule_update_any, vdom_is_rendering,
     AnyValue, Attribute, AttributeValue, CapturedError, Component, DynamicNode, Element, ElementId,
-    Event, Fragment, IntoDynNode, Mutation, MutationsVec, Properties, RenderReturn, ScopeId, Task,
+    Event, Fragment, IntoDynNode, Mutation, MutationsVec, Properties, ScopeId, Task,
     Template, TemplateAttribute, TemplateNode, VComponent, VNode, VNodeInner, VPlaceholder, VText,
     VirtualDom, WriteMutations,
 };

+ 12 - 4
packages/core/src/nodes.rs

@@ -20,8 +20,7 @@ pub type TemplateId = &'static str;
 ///
 /// Dioxus will do its best to immediately resolve any async components into a regular Element, but as an implementor
 /// you might need to handle the case where there's no node immediately ready.
-#[derive(Clone)]
-pub enum RenderReturn {
+pub(crate) enum RenderReturn {
     /// A currently-available element
     Ready(VNode),
 
@@ -31,6 +30,15 @@ pub enum RenderReturn {
     Aborted(VNode),
 }
 
+impl Clone for RenderReturn {
+    fn clone(&self) -> Self {
+        match self {
+            RenderReturn::Ready(node) => RenderReturn::Ready(node.clone_mounted()),
+            RenderReturn::Aborted(node) => RenderReturn::Aborted(node.clone_mounted()),
+        }
+    }
+}
+
 impl Default for RenderReturn {
     fn default() -> Self {
         RenderReturn::Aborted(VNode::placeholder())
@@ -125,8 +133,8 @@ impl Deref for VNode {
 }
 
 impl VNode {
-    /// Clone the element while retaining the mounted parent of the node
-    pub(crate) fn clone_with_parent(&self) -> Self {
+    /// Clone the element while retaining the mount information of the node
+    pub(crate) fn clone_mounted(&self) -> Self {
         Self {
             vnode: self.vnode.clone(),
             mount: self.mount.clone(),

+ 1 - 1
packages/core/src/virtual_dom.rs

@@ -556,10 +556,10 @@ impl VirtualDom {
         self.flush_templates(to);
         let _runtime = RuntimeGuard::new(self.runtime.clone());
         let new_nodes = self.run_scope(ScopeId::ROOT);
-        self.scopes[ScopeId::ROOT.0].last_rendered_node = Some(new_nodes.clone());
 
         // Rebuilding implies we append the created elements to the root
         let m = self.create_scope(to, ScopeId::ROOT, &new_nodes, None);
+
         to.append_children(ElementId(0), m);
     }