Browse Source

fix parents in placeholder diffing

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

+ 1 - 1
docs/guide/examples/readme_expanded.rs

@@ -85,7 +85,7 @@ fn app(cx: Scope) -> Element {
                 };
                 // The VNode is a reference to the template with the dynamic parts of the rsx
                 ::dioxus::core::VNode {
-                    parent: None,
+                    parent: Default::default(),
                     key: None,
                     // The static template this node will use. The template is stored in a Cell so it can be replaced with a new template when hot rsx reloading is enabled
                     template: std::cell::Cell::new(TEMPLATE),

+ 22 - 3
packages/core/src/create.rs

@@ -192,7 +192,15 @@ impl<'b> VirtualDom {
                 };
                 self.create_dynamic_node(template_ref, node)
             }
-            Placeholder(VPlaceholder { id }) => {
+            Placeholder(VPlaceholder { id, parent }) => {
+                let template_ref = ElementRef {
+                    path: ElementPath {
+                        path: &template.template.get().node_paths[idx],
+                    },
+                    template: &template,
+                    scope: self.runtime.current_scope_id().unwrap_or(ScopeId(0)),
+                };
+                parent.set(Some(self.next_element_ref(template_ref)));
                 let id = self.set_slot(id);
                 self.mutations.push(CreatePlaceholder { id });
                 1
@@ -510,6 +518,9 @@ impl<'b> VirtualDom {
         // Make sure the text node is assigned to the correct element
         placeholder.id.set(Some(id));
 
+        // Assign the placeholder's parent
+        placeholder.parent.set(Some(self.next_element_ref(parent)));
+
         // Assign the ID to the existing node in the template
         self.mutations.push(AssignId {
             path: &parent.path.path[1..],
@@ -538,7 +549,7 @@ impl<'b> VirtualDom {
                 self.assign_boundary_ref(parent, t);
                 self.create_scope(scope, t)
             }
-            Aborted(t) => self.mount_aborted(t),
+            Aborted(t) => self.mount_aborted(t, parent),
         }
     }
 
@@ -554,10 +565,18 @@ impl<'b> VirtualDom {
             .unwrap_or_else(|| component.scope.get().unwrap())
     }
 
-    fn mount_aborted(&mut self, placeholder: &VPlaceholder) -> usize {
+    fn mount_aborted(
+        &mut self,
+        placeholder: &VPlaceholder,
+        parent: Option<ElementRef<'b>>,
+    ) -> usize {
         let id = self.next_element();
         self.mutations.push(Mutation::CreatePlaceholder { id });
         placeholder.id.set(Some(id));
+        placeholder
+            .parent
+            .set(parent.map(|parent| self.next_element_ref(parent)));
+
         1
     }
 

+ 22 - 5
packages/core/src/diff.rs

@@ -42,11 +42,18 @@ impl<'b> VirtualDom {
                 (Ready(l), Aborted(p)) => self.diff_ok_to_err(l, p),
 
                 // Just move over the placeholder
-                (Aborted(l), Aborted(r)) => r.id.set(l.id.get()),
+                (Aborted(l), Aborted(r)) => {
+                    r.id.set(l.id.get());
+                    r.parent.set(l.parent.get())
+                }
 
                 // Placeholder becomes something
                 // We should also clear the error now
-                (Aborted(l), Ready(r)) => self.replace_placeholder(l, [r], todo!()),
+                (Aborted(l), Ready(r)) => self.replace_placeholder(
+                    l,
+                    [r],
+                    self.element_refs[l.parent.get().expect("root should not be none").0],
+                ),
             };
         }
         self.runtime.scope_stack.borrow_mut().pop();
@@ -55,6 +62,7 @@ impl<'b> VirtualDom {
     fn diff_ok_to_err(&mut self, l: &'b VNode<'b>, p: &'b VPlaceholder) {
         let id = self.next_element();
         p.id.set(Some(id));
+        p.parent.set(l.parent.get());
         self.mutations.push(Mutation::CreatePlaceholder { id });
 
         let pre_edits = self.mutations.edits.len();
@@ -164,10 +172,13 @@ impl<'b> VirtualDom {
         match (left_node, right_node) {
             (Text(left), Text(right)) => self.diff_vtext(left, right),
             (Fragment(left), Fragment(right)) => self.diff_non_empty_fragment(left, right, parent),
-            (Placeholder(left), Placeholder(right)) => right.id.set(left.id.get()),
+            (Placeholder(left), Placeholder(right)) => {
+                right.id.set(left.id.get());
+                right.parent.set(left.parent.get())
+            },
             (Component(left), Component(right)) => self.diff_vcomponent(left, right, Some(parent)),
             (Placeholder(left), Fragment(right)) => self.replace_placeholder(left, *right, parent),
-            (Fragment(left), Placeholder(right)) => self.node_to_placeholder(left, right),
+            (Fragment(left), Placeholder(right)) => self.node_to_placeholder(left, right, parent),
             _ => todo!("This is an usual custom case for dynamic nodes. We don't know how to handle it yet."),
         };
     }
@@ -838,11 +849,17 @@ impl<'b> VirtualDom {
         };
     }
 
-    fn node_to_placeholder(&mut self, l: &'b [VNode<'b>], r: &'b VPlaceholder) {
+    fn node_to_placeholder(
+        &mut self,
+        l: &'b [VNode<'b>],
+        r: &'b VPlaceholder,
+        parent: ElementRef<'b>,
+    ) {
         // Create the placeholder first, ensuring we get a dedicated ID for the placeholder
         let placeholder = self.next_element();
 
         r.id.set(Some(placeholder));
+        r.parent.set(Some(self.next_element_ref(parent)));
 
         self.mutations
             .push(Mutation::CreatePlaceholder { id: placeholder });

+ 2 - 0
packages/core/src/nodes.rs

@@ -373,6 +373,8 @@ impl<'a> VText<'a> {
 pub struct VPlaceholder {
     /// The ID of this node in the real DOM
     pub(crate) id: Cell<Option<ElementId>>,
+    /// The parent of this node
+    pub(crate) parent: Cell<Option<BubbleId>>,
 }
 
 impl VPlaceholder {

+ 2 - 1
packages/fullstack/src/hooks/server_cached.rs

@@ -12,9 +12,10 @@ use serde::{de::DeserializeOwned, Serialize};
 /// use dioxus_fullstack::prelude::*;
 ///
 /// fn app(cx: Scope) -> Element {
-///    let state1 = use_state(cx, || from_server(|| {
+///    let state1 = use_state(cx, || server_cached(|| {
 ///       1234
 ///    }));
+///    todo!()
 /// }
 /// ```
 pub fn server_cached<O: 'static + Serialize + DeserializeOwned>(server_fn: impl Fn() -> O) -> O {

+ 1 - 1
packages/native-core/tests/fuzzing.rs

@@ -255,7 +255,7 @@ fn create_random_element(cx: Scope<DepthProps>) -> Element {
             println!("{template:#?}");
             let node = VNode {
                 key: None,
-                parent: None,
+                parent: Default::default(),
                 template: Cell::new(template),
                 root_ids: dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump())
                     .into(),