yew/functional/hooks/use_callback.rs
1use std::rc::Rc;
2
3use crate::callback::Callback;
4use crate::functional::{hook, use_memo};
5
6/// Get a immutable reference to a memoized `Callback`. Its state persists across renders.
7/// It will be recreated only if any of the dependencies changes value.
8///
9/// Memoization means it will only get recreated when provided dependencies update/change.
10/// This is useful when passing callbacks to optimized child components that rely on
11/// PartialEq to prevent unnecessary renders.
12///
13/// # Example
14///
15/// ```rust
16/// # use yew::prelude::*;
17/// #
18/// #[derive(Properties, PartialEq)]
19/// pub struct Props {
20/// pub callback: Callback<String, String>,
21/// }
22///
23/// #[function_component(MyComponent)]
24/// fn my_component(props: &Props) -> Html {
25/// let greeting = props.callback.emit("Yew".to_string());
26///
27/// html! {
28/// <>{ &greeting }</>
29/// }
30/// }
31///
32/// #[function_component(UseCallback)]
33/// fn callback() -> Html {
34/// let counter = use_state(|| 0);
35/// let onclick = {
36/// let counter = counter.clone();
37/// Callback::from(move |_| counter.set(*counter + 1))
38/// };
39///
40/// // This callback depends on (), so it's created only once, then MyComponent
41/// // will be rendered only once even when you click the button multiple times.
42/// let callback = use_callback((), move |name, _| format!("Hello, {}!", name));
43///
44/// // It can also be used for events, this callback depends on `counter`.
45/// let oncallback = use_callback(counter.clone(), move |_e, counter| {
46/// let _ = **counter;
47/// });
48///
49/// html! {
50/// <div>
51/// <button {onclick}>{ "Increment value" }</button>
52/// <button onclick={oncallback}>{ "Callback" }</button>
53/// <p>
54/// <b>{ "Current value: " }</b>
55/// { *counter }
56/// </p>
57/// <MyComponent {callback} />
58/// </div>
59/// }
60/// }
61/// ```
62#[hook]
63pub fn use_callback<IN, OUT, F, D>(deps: D, f: F) -> Callback<IN, OUT>
64where
65 IN: 'static,
66 OUT: 'static,
67 F: Fn(IN, &D) -> OUT + 'static,
68 D: PartialEq + 'static,
69{
70 let deps = Rc::new(deps);
71
72 (*use_memo(deps, move |deps| {
73 let deps = deps.clone();
74 let f = move |value: IN| f(value, deps.as_ref());
75 Callback::from(f)
76 }))
77 .clone()
78}