From eb60cbd8f97c1b4d47ff957714c453a746b31f6f Mon Sep 17 00:00:00 2001 From: Martin Molzer Date: Thu, 16 Dec 2021 22:40:30 +0100 Subject: [PATCH] fix #2206 --- packages/yew/src/virtual_dom/vtag.rs | 45 ++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/packages/yew/src/virtual_dom/vtag.rs b/packages/yew/src/virtual_dom/vtag.rs index 9e6130ec03c..813b3e69bb8 100644 --- a/packages/yew/src/virtual_dom/vtag.rs +++ b/packages/yew/src/virtual_dom/vtag.rs @@ -476,7 +476,11 @@ impl VDiff for VTag { if parent.remove_child(&node).is_err() { console::warn!("Node not found to remove VTag"); } - self.node_ref.set(None); + // It could be that the ref was already reused when rendering another element. + // Only unset the ref it still belongs to our node + if self.node_ref.get().as_ref() == Some(&node) { + self.node_ref.set(None); + } } /// Renders virtual tag over DOM [Element], but it also compares this with an ancestor [VTag] @@ -514,7 +518,9 @@ impl VDiff for VTag { VNode::VTag(mut a) => { // Preserve the reference that already exists let el = a.reference.take().unwrap(); - a.node_ref.set(None); + if self.node_ref.get().as_ref() == self.reference.as_deref() { + a.node_ref.set(None); + } (Some(a), el) } _ => unsafe { unreachable_unchecked() }, @@ -1130,6 +1136,41 @@ mod tests { "node_ref_a should have been reset when the element was reused." ); } + + #[test] + fn vtag_should_not_touch_newly_bound_refs() { + let scope = test_scope(); + let parent = document().create_element("div").unwrap(); + document().body().unwrap().append_child(&parent).unwrap(); + + let test_ref = NodeRef::default(); + let mut before = html! { + <> +
+ + }; + let mut after = html! { + <> +
+
+ + }; + // The point of this diff is to first render the "after" div and then detach the "before" div, + // while both should be bound to the same node ref + + before.apply(&scope, &parent, NodeRef::default(), None); + after.apply(&scope, &parent, NodeRef::default(), Some(before)); + + assert_eq!( + test_ref + .get() + .unwrap() + .dyn_ref::() + .unwrap() + .outer_html(), + "
" + ); + } } #[cfg(test)]