From cc1a2384031b0f0f073b79f23164b929ca6c29df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?sebastian=C2=AE?= Date: Thu, 18 Dec 2025 23:53:06 -0800 Subject: [PATCH] Add documentation for optional cleanup support of onmounted --- .../src/essentials/advanced/breaking_out.md | 21 ++++++++++ .../0.7/src/essentials/advanced/lifecycle.md | 19 +++++++++ .../src/doc_examples/breaking_out.rs | 42 +++++++++++++++++++ 3 files changed, 82 insertions(+) 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 2de0eec7d7..b175e333fe 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 44f41ff617..303cccd796 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 d97f2a8332..3da843e266 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 +}