diff --git a/examples/drops.rs b/examples/drops.rs new file mode 100644 index 000000000..71a791990 --- /dev/null +++ b/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!"); + } +} diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs index a1a211527..13ded6f5d 100644 --- a/packages/core/src/arena.rs +++ b/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() { diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 410eec55c..42cb9c3ff 100644 --- a/packages/core/src/diff.rs +++ b/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 {