yew/functional/hooks/use_memo.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
use std::borrow::Borrow;
use std::rc::Rc;
use super::use_mut_ref;
use crate::functional::hook;
/// Get a immutable reference to a memoized value.
///
/// This version allows for a key cache key derivation that only borrows
/// like the original argument. For example, using ` K = Rc<D>`, we only
/// create a shared reference to dependencies *after* they change.
#[hook]
pub(crate) fn use_memo_base<T, F, D, K>(f: F, deps: D) -> Rc<T>
where
T: 'static,
F: FnOnce(D) -> (T, K),
K: 'static + Borrow<D>,
D: PartialEq,
{
struct MemoState<T, K> {
memo_key: K,
result: Rc<T>,
}
let state = use_mut_ref(|| -> Option<MemoState<T, K>> { None });
let mut state = state.borrow_mut();
match &*state {
Some(existing) if existing.memo_key.borrow() != &deps => {
// Drop old state if it's outdated
*state = None;
}
_ => {}
};
let state = state.get_or_insert_with(|| {
let (result, memo_key) = f(deps);
let result = Rc::new(result);
MemoState { result, memo_key }
});
state.result.clone()
}
/// Get a immutable reference to a memoized value.
///
/// Memoization means it will only get recalculated when provided dependencies update/change.
///
/// It can be useful for keeping things in scope for the lifetime of the component,
/// so long as you don't store a clone of the resulting `Rc` anywhere that outlives the component.
///
/// # Example
///
/// ```rust
/// use yew::prelude::*;
///
/// #[derive(PartialEq, Properties)]
/// pub struct Props {
/// pub step: usize,
/// }
///
/// #[function_component(UseMemo)]
/// fn memo(props: &Props) -> Html {
/// // Will only get recalculated if `props.step` value changes
/// let message = use_memo(props.step, |step| {
/// format!("{}. Do Some Expensive Calculation", step)
/// });
///
/// html! {
/// <div>
/// <span>{ (*message).clone() }</span>
/// </div>
/// }
/// }
/// ```
#[hook]
pub fn use_memo<T, F, D>(deps: D, f: F) -> Rc<T>
where
T: 'static,
F: FnOnce(&D) -> T,
D: 'static + PartialEq,
{
use_memo_base(|d| (f(&d), d), deps)
}