From b43dfb1f678d5f9444d0b0a218af8ed4a9055eba Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 9 Jan 2024 11:35:55 -0600 Subject: [PATCH] fix mounted information --- packages/core/src/arena.rs | 9 -------- packages/core/src/diff/component.rs | 13 ++++++----- packages/core/src/diff/node.rs | 36 ++++++++++++++++++----------- packages/core/src/lib.rs | 3 +-- packages/core/src/nodes.rs | 16 +++++++++---- packages/core/src/virtual_dom.rs | 2 +- 6 files changed, 44 insertions(+), 35 deletions(-) diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs index cd5819756..baabd318c 100644 --- a/packages/core/src/arena.rs +++ b/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 { 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)] diff --git a/packages/core/src/diff/component.rs b/packages/core/src/diff/component.rs index f148face4..95185d128 100644 --- a/packages/core/src/diff/component.rs +++ b/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, ) -> 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) } } diff --git a/packages/core/src/diff/node.rs b/packages/core/src/diff/node.rs index 8af2689c9..3ec611f35 100644 --- a/packages/core/src/diff/node.rs +++ b/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, diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 95a12ba54..6708b3b60 100644 --- a/packages/core/src/lib.rs +++ b/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, }; diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 208017110..3bef82f4a 100644 --- a/packages/core/src/nodes.rs +++ b/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(), diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index b3ca1ec52..08e3d5d34 100644 --- a/packages/core/src/virtual_dom.rs +++ b/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); }