Allow functions returning unit in use_effect (#2849)

* Use TearDown trait as destructor for use_effect

* Docs

* no default tear_down
This commit is contained in:
Muhammad Hamza 2022-08-28 19:33:42 +05:00 committed by GitHub
parent cffb7c5e7e
commit 0e0d6949f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -2,11 +2,27 @@ use std::cell::RefCell;
use crate::functional::{hook, Effect, Hook, HookContext};
/// Trait describing the destructor of [`use_effect`] hook.
pub trait TearDown: Sized + 'static {
/// The function that is executed when destructor is called
fn tear_down(self);
}
impl TearDown for () {
fn tear_down(self) {}
}
impl<F: FnOnce() + 'static> TearDown for F {
fn tear_down(self) {
self()
}
}
struct UseEffectBase<T, F, D>
where
F: FnOnce(&T) -> D + 'static,
T: 'static,
D: FnOnce() + 'static,
D: TearDown,
{
runner_with_deps: Option<(T, F)>,
destructor: Option<D>,
@ -18,7 +34,7 @@ impl<T, F, D> Effect for RefCell<UseEffectBase<T, F, D>>
where
F: FnOnce(&T) -> D + 'static,
T: 'static,
D: FnOnce() + 'static,
D: TearDown,
{
fn rendered(&self) {
let mut this = self.borrow_mut();
@ -29,7 +45,7 @@ where
}
if let Some(de) = this.destructor.take() {
de();
de.tear_down();
}
let new_destructor = runner(&deps);
@ -44,11 +60,11 @@ impl<T, F, D> Drop for UseEffectBase<T, F, D>
where
F: FnOnce(&T) -> D + 'static,
T: 'static,
D: FnOnce() + 'static,
D: TearDown,
{
fn drop(&mut self) {
if let Some(destructor) = self.destructor.take() {
destructor()
destructor.tear_down()
}
}
}
@ -60,13 +76,13 @@ fn use_effect_base<T, D>(
) -> impl Hook<Output = ()>
where
T: 'static,
D: FnOnce() + 'static,
D: TearDown,
{
struct HookProvider<T, F, D>
where
F: FnOnce(&T) -> D + 'static,
T: 'static,
D: FnOnce() + 'static,
D: TearDown,
{
runner: F,
deps: T,
@ -77,7 +93,7 @@ where
where
F: FnOnce(&T) -> D + 'static,
T: 'static,
D: FnOnce() + 'static,
D: TearDown,
{
type Output = ();
@ -141,11 +157,20 @@ where
/// }
/// }
/// ```
///
/// # Destructor
///
/// Any type implementing [`TearDown`] can be used as destructor, which is called when the component
/// is re-rendered
///
/// ## Tip
///
/// The callback can return [`()`] if there is no destructor to run.
#[hook]
pub fn use_effect<F, D>(f: F)
where
F: FnOnce() -> D + 'static,
D: FnOnce() + 'static,
D: TearDown,
{
use_effect_base(|_| f(), (), |_, _| true);
}
@ -176,7 +201,6 @@ where
/// use_effect_with_deps(
/// move |_| {
/// log!(" Is loading prop changed!");
/// || ()
/// },
/// is_loading,
/// );
@ -201,7 +225,6 @@ where
/// use_effect_with_deps(
/// move |_| {
/// log!("I got rendered, yay!");
/// || ()
/// },
/// (),
/// );
@ -232,12 +255,18 @@ where
/// html! { "Hello" }
/// }
/// ```
///
/// Any type implementing [`TearDown`] can be used as destructor
///
/// ### Tip
///
/// The callback can return [`()`] if there is no destructor to run.
#[hook]
pub fn use_effect_with_deps<T, F, D>(f: F, deps: T)
where
T: PartialEq + 'static,
F: FnOnce(&T) -> D + 'static,
D: FnOnce() + 'static,
D: TearDown,
{
use_effect_base(f, deps, |lhs, rhs| lhs != rhs)
}