diff --git a/docs-src/0.7/src/essentials/advanced/breaking_out.md b/docs-src/0.7/src/essentials/advanced/breaking_out.md index 2de0eec7d..b175e333f 100644 --- a/docs-src/0.7/src/essentials/advanced/breaking_out.md +++ b/docs-src/0.7/src/essentials/advanced/breaking_out.md @@ -61,6 +61,27 @@ DemoFrame { } ``` +### Returning a Cleanup Closure + +You can return a cleanup closure from your `onmounted` handler. This closure runs when the element is removed from the DOM, allowing you to clean up resources like animations, event listeners, or observers: + +```rust, no_run +{{#include ../docs-router/src/doc_examples/breaking_out.rs:onmounted_cleanup}} +``` +```inject-dioxus +DemoFrame { + breaking_out::OnMountedWithCleanup {} +} +``` + +This pattern is useful when you need to: +- Stop animations running on an element +- Remove event listeners added to the window or document +- Clear intervals or timeouts +- Disconnect observers (ResizeObserver, IntersectionObserver, etc.) + +> The cleanup runs before the element is removed, so you still have access to the DOM state if needed. + ## Down casting web sys events Dioxus provides platform agnostic wrappers over each event type. These wrappers are often nicer to interact with than the raw event types, but they can be more limited. If you are targeting web, you can downcast the event with the `as_web_event` method to get the underlying web-sys event: diff --git a/docs-src/0.7/src/essentials/advanced/lifecycle.md b/docs-src/0.7/src/essentials/advanced/lifecycle.md index 44f41ff61..303cccd79 100644 --- a/docs-src/0.7/src/essentials/advanced/lifecycle.md +++ b/docs-src/0.7/src/essentials/advanced/lifecycle.md @@ -62,3 +62,22 @@ DemoFrame { component_lifecycle::DropDemo {} } ``` + +## Element Cleanup with `onmounted` + +While `use_drop` runs when a component is dropped, you can also run cleanup code when a specific element is removed from the DOM. Return a cleanup closure from your `onmounted` handler: + +```rust, no_run +div { + onmounted: move |e| { + let el = e.data(); + start_animation(el.clone()); + // Return cleanup that runs when element is removed + move || stop_animation(el) + }, +} +``` + +This is useful when you need cleanup tied to a specific element's lifetime rather than the whole component. For example, stopping animations on individual elements when they're removed. + +See [Breaking Out - onmounted](./breaking_out.md#getting-access-to-elements-with-onmounted) for more details and a full example. diff --git a/packages/docs-router/src/doc_examples/breaking_out.rs b/packages/docs-router/src/doc_examples/breaking_out.rs index d97f2a833..3da843e26 100644 --- a/packages/docs-router/src/doc_examples/breaking_out.rs +++ b/packages/docs-router/src/doc_examples/breaking_out.rs @@ -2,6 +2,7 @@ use dioxus::prelude::*; pub use downcast::Downcast; pub use eval::Eval; pub use onmounted_::OnMounted; +pub use onmounted_cleanup::OnMountedWithCleanup; pub use use_effect::Canvas; pub use web_sys::WebSys; @@ -143,3 +144,44 @@ mod onmounted_ { } // ANCHOR_END: onmounted } + +mod onmounted_cleanup { + use super::*; + + // ANCHOR: onmounted_cleanup + pub fn OnMountedWithCleanup() -> Element { + let mut show_element = use_signal(|| true); + let mut status = use_signal(|| "Element not mounted yet".to_string()); + + rsx! { + div { + button { + onclick: move |_| show_element.toggle(), + if show_element() { "Remove Element" } else { "Add Element" } + } + div { "Status: {status}" } + if show_element() { + div { + class: "p-4 bg-blue-100 rounded mt-2", + onmounted: move |e| { + let el = e.data(); + start_animation(el.clone(), status); + // Return a cleanup closure that runs when the element is removed + move || stop_animation(el, status) + }, + "Animated element" + } + } + } + } + } + + fn start_animation(_el: std::rc::Rc, mut status: Signal) { + status.set("Animation started".to_string()); + } + + fn stop_animation(_el: std::rc::Rc, mut status: Signal) { + status.set("Animation stopped (cleanup ran)".to_string()); + } + // ANCHOR_END: onmounted_cleanup +}