wasm_react/hooks/
use_memo.rs

1use super::{use_ref, Deps, RefContainer};
2use std::cell::Ref;
3use wasm_bindgen::UnwrapThrowExt;
4
5/// Allows access to the underlying memoized data persisted with [`use_memo()`].
6#[derive(Debug)]
7pub struct Memo<T>(RefContainer<Option<T>>);
8
9impl<T: 'static> Memo<T> {
10  /// Returns a reference to the underlying memoized data.
11  pub fn value(&self) -> Ref<'_, T> {
12    Ref::map(self.0.current(), |x| {
13      x.as_ref().expect_throw("no memo data available")
14    })
15  }
16}
17
18impl<T> Clone for Memo<T> {
19  fn clone(&self) -> Self {
20    Self(self.0.clone())
21  }
22}
23
24/// Returns a persisted, memoized value.
25///
26/// This will recompute the value with the given closure whenever the given
27/// dependencies has changed from last render. This optimization helps to avoid
28/// expensive calculations on every render.
29///
30/// # Example
31///
32/// ```
33/// # use wasm_react::{*, hooks::*};
34/// #
35/// # fn compute_expensive_value(a: (), b: ()) -> &'static str { "" }
36/// # struct C { a: (), b:() };
37/// # impl C {
38/// fn render(&self) -> VNode {
39///   let a = self.a;
40///   let b = self.b;
41///   let memo = use_memo(|| compute_expensive_value(a, b), Deps::some((a, b)));
42///
43///   let vnode = h!(div).build(*memo.value());
44///   vnode
45/// }
46/// # }
47/// ```
48pub fn use_memo<T, D>(create: impl FnOnce() -> T, deps: Deps<D>) -> Memo<T>
49where
50  T: 'static,
51  D: PartialEq + 'static,
52{
53  let mut deps_ref_container = use_ref(None::<Deps<D>>);
54  let mut value_ref_container = use_ref(None::<T>);
55
56  let need_update = {
57    let current = deps_ref_container.current();
58    let old_deps = current.as_ref();
59
60    deps.is_all() || Some(&deps) != old_deps
61  };
62
63  if need_update {
64    deps_ref_container.set_current(Some(deps));
65    value_ref_container.set_current(Some(create()));
66  }
67
68  Memo(value_ref_container)
69}