Browse Source

Merge pull request #771 from DioxusLabs/jk/fix-scope-drop

fix: scopes not dropping their hooks when being hidden form the dom
Jon Kelley 2 năm trước cách đây
mục cha
commit
34b0a0d03b
3 tập tin đã thay đổi với 48 bổ sung11 xóa
  1. 36 0
      examples/drops.rs
  2. 7 2
      packages/core/src/arena.rs
  3. 5 9
      packages/core/src/diff.rs

+ 36 - 0
examples/drops.rs

@@ -0,0 +1,36 @@
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus_desktop::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+    let count = if cx.generation() % 2 == 0 { 10 } else { 0 };
+
+    println!("Generation: {}", cx.generation());
+
+    if cx.generation() < 10 {
+        cx.needs_update();
+    }
+
+    render! {
+        (0..count).map(|_| rsx!{
+            drop_child {}
+        })
+    }
+}
+
+fn drop_child(cx: Scope) -> Element {
+    cx.use_hook(|| Drops);
+    render! {
+        div{}
+    }
+}
+
+struct Drops;
+
+impl Drop for Drops {
+    fn drop(&mut self) {
+        println!("Dropped!");
+    }
+}

+ 7 - 2
packages/core/src/arena.rs

@@ -1,8 +1,8 @@
 use std::ptr::NonNull;
 
 use crate::{
-    nodes::RenderReturn, nodes::VNode, virtual_dom::VirtualDom, AttributeValue, DynamicNode,
-    ScopeId,
+    innerlude::DirtyScope, nodes::RenderReturn, nodes::VNode, virtual_dom::VirtualDom,
+    AttributeValue, DynamicNode, ScopeId,
 };
 use bumpalo::boxed::Box as BumpBox;
 
@@ -89,6 +89,11 @@ impl VirtualDom {
 
     // Drop a scope and all its children
     pub(crate) fn drop_scope(&mut self, id: ScopeId) {
+        self.dirty_scopes.remove(&DirtyScope {
+            height: self.scopes[id.0].height,
+            id,
+        });
+
         self.ensure_drop_safety(id);
 
         if let Some(root) = self.scopes[id.0].as_ref().try_root_node() {

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

@@ -916,29 +916,25 @@ impl<'b> VirtualDom {
     }
 
     fn remove_component_node(&mut self, comp: &VComponent, gen_muts: bool) {
+        // Remove the component reference from the vcomponent so they're not tied together
         let scope = comp
             .scope
             .take()
             .expect("VComponents to always have a scope");
 
+        // Remove the component from the dom
         match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } {
             RenderReturn::Ready(t) => self.remove_node(t, gen_muts),
             RenderReturn::Aborted(placeholder) => self.remove_placeholder(placeholder, gen_muts),
             _ => todo!(),
         };
 
+        // Restore the props back to the vcomponent in case it gets rendered again
         let props = self.scopes[scope.0].props.take();
-
-        self.dirty_scopes.remove(&DirtyScope {
-            height: self.scopes[scope.0].height,
-            id: scope,
-        });
-
         *comp.props.borrow_mut() = unsafe { std::mem::transmute(props) };
 
-        // make sure to wipe any of its props and listeners
-        self.ensure_drop_safety(scope);
-        self.scopes.remove(scope.0);
+        // Now drop all the resouces
+        self.drop_scope(scope);
     }
 
     fn find_first_element(&self, node: &'b VNode<'b>) -> ElementId {