wasm_react/hooks/use_transition.rs
1use js_sys::Function;
2use wasm_bindgen::{prelude::Closure, JsCast, JsValue, UnwrapThrowExt};
3
4use crate::react_bindings;
5
6/// Allows access to the transition state.
7#[derive(Debug, Clone)]
8pub struct Transition {
9 is_pending: bool,
10 start_transition: Function,
11}
12
13impl Transition {
14 /// Returns whether the transition is active or not.
15 pub fn is_pending(&self) -> bool {
16 self.is_pending
17 }
18
19 /// Marks the updates in the given closure as transitions.
20 pub fn start(&mut self, f: impl FnOnce() + 'static) {
21 self
22 .start_transition
23 .call1(&JsValue::NULL, &Closure::once_into_js(f))
24 .expect_throw("unable to call start function");
25 }
26}
27
28/// Returns a stateful value for the pending state of the transition, and a
29/// function to start it.
30///
31/// # Example
32///
33/// ```
34/// # use wasm_react::{*, hooks::*};
35/// #
36/// # fn render() -> VNode {
37/// let count = use_state(|| 0);
38/// let transition = use_transition();
39///
40/// h!(div).build((
41/// transition.is_pending().then(||
42/// h!(div).build("Loading…")
43/// ),
44/// h!(button).on_click(&Callback::new({
45/// clones!(count, mut transition);
46///
47/// move |_| {
48/// transition.start({
49/// clones!(mut count);
50///
51/// move || {
52/// count.set(|c| c + 1);
53/// }
54/// });
55/// }
56/// })).build("Increment"),
57/// ))
58/// # }
59/// ```
60pub fn use_transition() -> Transition {
61 let result = react_bindings::use_transition();
62
63 let is_pending = result
64 .get(0)
65 .as_bool()
66 .expect_throw("unable to read pending state from transition");
67 let start_transition = result
68 .get(1)
69 .dyn_into::<Function>()
70 .expect_throw("unable to read start function from transition");
71
72 Transition {
73 is_pending,
74 start_transition,
75 }
76}