Browse Source

Merge pull request #1139 from Demonthos/add-onunmount-hook

Add on unmount hook
Jonathan Kelley 1 năm trước cách đây
mục cha
commit
b25501af48

+ 1 - 0
packages/hooks/Cargo.toml

@@ -20,3 +20,4 @@ log = { workspace = true }
 futures-util = { workspace = true, default-features = false }
 dioxus-core = { workspace = true }
 dioxus = { workspace = true }
+web-sys = { version = "0.3.64", features = ["Document", "Window", "Element"] }

+ 3 - 0
packages/hooks/src/lib.rs

@@ -50,6 +50,9 @@ macro_rules! to_owned {
     };
 }
 
+mod use_on_unmount;
+pub use use_on_unmount::*;
+
 mod usecontext;
 pub use usecontext::*;
 

+ 74 - 0
packages/hooks/src/use_on_unmount.rs

@@ -0,0 +1,74 @@
+/// Creats a callback that will be run before the component is removed. This can be used to clean up side effects from the component (created with use_effect)
+///
+/// Example:
+/// ```rust
+/// use dioxus::prelude::*;
+
+/// fn app(cx: Scope) -> Element {
+///     let state = use_state(cx, || true);
+///     render! {
+///         for _ in 0..100 {
+///             h1 {
+///                 "spacer"
+///             }
+///         }
+///         if **state {
+///             render! {
+///                 child_component {}
+///             }
+///         }
+///         button {
+///             onclick: move |_| {
+///                 state.set(!*state.get());
+///             },
+///             "Unmount element"
+///         }
+///     }
+/// }
+
+/// fn child_component(cx: Scope) -> Element {
+///     let original_scroll_position = use_state(cx, || 0.0);
+///     use_effect(cx, (), move |_| {
+///         to_owned![original_scroll_position];
+///         async move {
+///             let window = web_sys::window().unwrap();
+///             let document = window.document().unwrap();
+///             let element = document.get_element_by_id("my_element").unwrap();
+///             element.scroll_into_view();
+///             original_scroll_position.set(window.scroll_y().unwrap());
+///         }
+///     });
+
+///     use_on_unmount(cx, {
+///         to_owned![original_scroll_position];
+///         /// restore scroll to the top of the page
+///         move || {
+///             let window = web_sys::window().unwrap();
+///             window.scroll_with_x_and_y(*original_scroll_position.current(), 0.0);
+///         }
+///     });
+
+///     render!{
+///         div {
+///             id: "my_element",
+///             "hello"
+///         }
+///     }
+/// }
+/// ```
+pub fn use_on_unmount<D: FnOnce() + 'static>(cx: &dioxus_core::ScopeState, destroy: D) {
+    cx.use_hook(|| LifeCycle {
+        ondestroy: Some(destroy),
+    });
+}
+
+struct LifeCycle<D: FnOnce()> {
+    ondestroy: Option<D>,
+}
+
+impl<D: FnOnce()> Drop for LifeCycle<D> {
+    fn drop(&mut self) {
+        let f = self.ondestroy.take().unwrap();
+        f();
+    }
+}