fix: scopes not dropping their hooks

This commit is contained in:
Jonathan Kelley 2023-01-15 10:02:24 -08:00
parent 1737c55575
commit 69a347a551
3 changed files with 48 additions and 11 deletions

36
examples/drops.rs Normal file
View file

@ -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!{
Comp {}
})
}
}
fn Comp(cx: Scope) -> Element {
cx.use_hook(|| Drops);
render! {
div{}
}
}
struct Drops;
impl Drop for Drops {
fn drop(&mut self) {
println!("Dropped!");
}
}

View file

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

View file

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