Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add use_callback hook * Simply use_callback
- Loading branch information
Showing
8 changed files
with
244 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
use crate::callback::Callback; | ||
use crate::functional::{hook, use_memo}; | ||
|
||
/// Get a immutable reference to a memoized `Callback`. | ||
/// | ||
/// Memoization means it will only get recreated when provided dependencies update/change. | ||
/// This is useful when passing callbacks to optimized child components that rely on | ||
/// PartialEq to prevent unnecessary renders. | ||
/// | ||
/// # Example | ||
/// | ||
/// ```rust | ||
/// # use yew::prelude::*; | ||
/// # | ||
/// #[derive(Properties, PartialEq)] | ||
/// pub struct Props { | ||
/// pub callback: Callback<String, String>, | ||
/// } | ||
/// | ||
/// #[function_component(MyComponennt)] | ||
/// fn my_component(props: &Props) -> Html { | ||
/// let greeting = props.callback.emit("Yew".to_string()); | ||
/// | ||
/// html! { | ||
/// <>{ &greeting }</> | ||
/// } | ||
/// } | ||
/// | ||
/// #[function_component(UseCallback)] | ||
/// fn callback() -> Html { | ||
/// let counter = use_state(|| 0); | ||
/// let onclick = { | ||
/// let counter = counter.clone(); | ||
/// Callback::from(move |_| counter.set(*counter + 1)) | ||
/// }; | ||
/// | ||
/// // This callback depends on (), so it's created only once, then MyComponennt | ||
/// // will be rendered only once even when you click the button mutiple times. | ||
/// let callback = use_callback( | ||
/// move |name| format!("Hello, {}!", name), | ||
/// () | ||
/// ); | ||
/// | ||
/// // It can also be used for events. | ||
/// let oncallback = { | ||
/// let counter = counter.clone(); | ||
/// use_callback( | ||
/// move |_e| (), | ||
/// counter | ||
/// ) | ||
/// }; | ||
/// | ||
/// html! { | ||
/// <div> | ||
/// <button {onclick}>{ "Increment value" }</button> | ||
/// <button onclick={oncallback}>{ "Callback" }</button> | ||
/// <p> | ||
/// <b>{ "Current value: " }</b> | ||
/// { *counter } | ||
/// </p> | ||
/// <MyComponennt {callback} /> | ||
/// </div> | ||
/// } | ||
/// } | ||
/// ``` | ||
#[hook] | ||
pub fn use_callback<IN, OUT, F, D>(f: F, deps: D) -> Callback<IN, OUT> | ||
where | ||
IN: 'static, | ||
OUT: 'static, | ||
F: Fn(IN) -> OUT + 'static, | ||
D: PartialEq + 'static, | ||
{ | ||
(*use_memo(move |_| Callback::from(f), deps)).clone() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#![cfg(feature = "wasm_test")] | ||
|
||
use std::sync::atomic::{AtomicBool, Ordering}; | ||
|
||
mod common; | ||
|
||
use common::obtain_result; | ||
use gloo::timers::future::sleep; | ||
use std::time::Duration; | ||
use wasm_bindgen_test::*; | ||
use yew::prelude::*; | ||
|
||
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); | ||
|
||
#[wasm_bindgen_test] | ||
async fn use_callback_works() { | ||
#[derive(Properties, PartialEq)] | ||
struct Props { | ||
callback: Callback<String, String>, | ||
} | ||
|
||
#[function_component(MyComponennt)] | ||
fn my_component(props: &Props) -> Html { | ||
let greeting = props.callback.emit("Yew".to_string()); | ||
|
||
static CTR: AtomicBool = AtomicBool::new(false); | ||
|
||
if CTR.swap(true, Ordering::Relaxed) { | ||
panic!("multiple times rendered!"); | ||
} | ||
|
||
html! { | ||
<div> | ||
{"The test output is: "} | ||
<div id="result">{&greeting}</div> | ||
{"\n"} | ||
</div> | ||
} | ||
} | ||
|
||
#[function_component(UseCallbackComponent)] | ||
fn use_callback_comp() -> Html { | ||
let state = use_state(|| 0); | ||
|
||
let callback = use_callback(move |name| format!("Hello, {}!", name), ()); | ||
|
||
use_effect(move || { | ||
if *state < 5 { | ||
state.set(*state + 1); | ||
} | ||
|
||
|| {} | ||
}); | ||
|
||
html! { | ||
<div> | ||
<MyComponennt {callback} /> | ||
</div> | ||
} | ||
} | ||
|
||
yew::Renderer::<UseCallbackComponent>::with_root( | ||
gloo_utils::document().get_element_by_id("output").unwrap(), | ||
) | ||
.render(); | ||
|
||
sleep(Duration::ZERO).await; | ||
|
||
let result = obtain_result(); | ||
assert_eq!(result.as_str(), "Hello, Yew!"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
website/docs/concepts/function-components/hooks/use-callback.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
--- | ||
title: "use_callback" | ||
--- | ||
|
||
`use_callback` is used for obtaining an immutable reference to a memoized `Callback`. | ||
Its state persists across renders. | ||
It will be recreated only if any of the dependencies values change. | ||
|
||
`use_callback` can be useful when passing callbacks to optimized child components that rely on | ||
PartialEq to prevent unnecessary renders. | ||
|
||
```rust | ||
use yew::prelude::*; | ||
|
||
#[derive(Properties, PartialEq)] | ||
pub struct Props { | ||
pub callback: Callback<String, String>, | ||
} | ||
|
||
#[function_component(MyComponennt)] | ||
fn my_component(props: &Props) -> Html { | ||
let greeting = props.callback.emit("Yew".to_string()); | ||
|
||
html! { | ||
<>{ &greeting }</> | ||
} | ||
} | ||
|
||
#[function_component(UseCallback)] | ||
fn callback() -> Html { | ||
let counter = use_state(|| 0); | ||
let onclick = { | ||
let counter = counter.clone(); | ||
Callback::from(move |_| counter.set(*counter + 1)) | ||
}; | ||
|
||
// This callback depends on (), so it's created only once, then MyComponennt | ||
// will be rendered only once even when you click the button mutiple times. | ||
let callback = use_callback( | ||
move |name| format!("Hello, {}!", name), | ||
() | ||
); | ||
|
||
// It can also be used for events. | ||
let oncallback = { | ||
let counter = counter.clone(); | ||
use_callback( | ||
move |_e| (), | ||
counter | ||
) | ||
}; | ||
|
||
html! { | ||
<div> | ||
<button {onclick}>{ "Increment value" }</button> | ||
<button onclick={oncallback}>{ "Callback" }</button> | ||
<p> | ||
<b>{ "Current value: " }</b> | ||
{ *counter } | ||
</p> | ||
<MyComponennt {callback} /> | ||
</div> | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
421b4e1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yew master branch benchmarks (Lower is better)
yew-struct-keyed 01_run1k
179.1905
237.946
0.75
yew-struct-keyed 02_replace1k
180.5605
231.9485
0.78
yew-struct-keyed 03_update10th1k_x16
324.7545
402.2355
0.81
yew-struct-keyed 04_select1k
63.3815
73.894
0.86
yew-struct-keyed 05_swap1k
77.0505
94.2395
0.82
yew-struct-keyed 06_remove-one-1k
28.3335
30.8645
0.92
yew-struct-keyed 07_create10k
2279.2725
2680.2865
0.85
yew-struct-keyed 08_create1k-after1k_x2
411.3745
498.7965
0.82
yew-struct-keyed 09_clear1k_x8
182.642
241.5745
0.76
yew-struct-keyed 21_ready-memory
1.4005584716796875
1.2447853088378906
1.13
yew-struct-keyed 22_run-memory
1.6612091064453125
1.45648193359375
1.14
yew-struct-keyed 23_update5-memory
1.70111083984375
1.5057640075683594
1.13
yew-struct-keyed 24_run5-memory
1.717632293701172
1.5095291137695312
1.14
yew-struct-keyed 25_run-clear-memory
1.421672821044922
1.1240959167480469
1.26
yew-struct-keyed 31_startup-ci
1730.362
1732.398
1.00
yew-struct-keyed 32_startup-bt
27.70800000000001
37.907999999999994
0.73
yew-struct-keyed 34_startup-totalbytes
330.546875
330.5556640625
1.00
This comment was automatically generated by workflow using github-action-benchmark.