diff --git a/packages/core/src/global_context.rs b/packages/core/src/global_context.rs index 854c6be86..7010acb07 100644 --- a/packages/core/src/global_context.rs +++ b/packages/core/src/global_context.rs @@ -4,6 +4,7 @@ use crate::{ Task, }; use std::future::Future; +use std::rc::Rc; use std::sync::Arc; /// Get the current scope id @@ -441,15 +442,10 @@ pub fn use_drop(destroy: D) { } } - // We need to impl clone for the lifecycle, but we don't want the drop handler for the closure to be called twice. - impl Clone for LifeCycle { - fn clone(&self) -> Self { - Self { ondestroy: None } - } - } - - use_hook(|| LifeCycle { - ondestroy: Some(destroy), + use_hook(|| { + Rc::new(LifeCycle { + ondestroy: Some(destroy), + }) }); } diff --git a/packages/core/tests/use_drop.rs b/packages/core/tests/use_drop.rs new file mode 100644 index 000000000..0333c467d --- /dev/null +++ b/packages/core/tests/use_drop.rs @@ -0,0 +1,67 @@ +//! Tests the use_drop hook +use dioxus::dioxus_core::use_drop; +use dioxus::prelude::*; +use std::sync::{Arc, Mutex}; + +type Shared = Arc>; + +#[derive(Clone, Props)] +struct AppProps { + render_child: Shared, + drop_count: Shared, +} + +impl PartialEq for AppProps { + fn eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.drop_count, &other.drop_count) + } +} + +fn app(props: AppProps) -> Element { + let render_child = props.render_child.clone(); + let render_child = *render_child.lock().unwrap(); + println!( + "Rendering app component with render_child: {}", + render_child + ); + rsx! { + if render_child { + child_component { + drop_count: props.drop_count.clone(), + render_child: props.render_child.clone() + } + } + } +} + +fn child_component(props: AppProps) -> Element { + println!("Rendering child component"); + use_drop(move || { + println!("Child component is being dropped"); + let mut count = props.drop_count.lock().unwrap(); + *count += 1; + }); + + rsx! {} +} + +#[test] +fn drop_runs() { + let drop_count = Arc::new(Mutex::new(0)); + let render_child = Arc::new(Mutex::new(true)); + let mut dom = VirtualDom::new_with_props( + app, + AppProps { drop_count: drop_count.clone(), render_child: render_child.clone() }, + ); + + dom.rebuild_in_place(); + + assert_eq!(*drop_count.lock().unwrap(), 0); + *render_child.lock().unwrap() = false; + + dom.mark_dirty(ScopeId::APP); + dom.render_immediate(&mut dioxus_core::NoOpMutations); + + assert_eq!(*drop_count.lock().unwrap(), 1); + *render_child.lock().unwrap() = false; +}