yew/functional/hooks/use_force_update.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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
use std::fmt;
use super::{Hook, HookContext};
use crate::functional::ReRender;
/// A handle which can be used to force a re-render of the associated
/// function component.
#[derive(Clone)]
pub struct UseForceUpdateHandle {
trigger: ReRender,
}
impl fmt::Debug for UseForceUpdateHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("UseForceUpdate").finish()
}
}
impl UseForceUpdateHandle {
/// Trigger an unconditional re-render of the associated function component
pub fn force_update(&self) {
(self.trigger)()
}
}
#[cfg(nightly_yew)]
mod feat_nightly {
use super::*;
impl FnOnce<()> for UseForceUpdateHandle {
type Output = ();
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
self.force_update()
}
}
impl FnMut<()> for UseForceUpdateHandle {
extern "rust-call" fn call_mut(&mut self, _args: ()) -> Self::Output {
self.force_update()
}
}
impl Fn<()> for UseForceUpdateHandle {
extern "rust-call" fn call(&self, _args: ()) -> Self::Output {
self.force_update()
}
}
}
/// This hook is used to manually force a function component to re-render.
///
/// # Note
///
/// Often, using this hook means that you're doing something wrong.
/// Try to use more specialized hooks, such as [`use_state`] and [`use_reducer`].
/// This hook should only be used when your component depends on external state where you
/// can't subscribe to changes, or as a low-level primitive to enable such a subscription-based
/// approach.
///
/// # Use-case
///
/// Use this hook when wrapping an API that doesn't expose precise subscription events for fetched
/// data. You could then, at some point, invalidate your local cache of the fetched data and trigger
/// a re-render to let the normal render flow of components tell you again which data to fetch, and
/// repopulate the cache accordingly.
///
/// A large externally managed cache, such as a app-wide cache for GraphQL data
/// should not rerender every component whenever new data arrives, but only those where a query
/// changed.
///
/// If the state of your component is not shared, you should need to use this hook.
///
/// # Example
///
/// This example implements a silly, manually updated display of the current time. The component
/// is re-rendered every time the button is clicked. You should usually use a timeout and
/// `use_state` to automatically trigger a re-render every second without having to use this hook.
///
/// ```rust
/// use yew::prelude::*;
///
/// #[function_component]
/// fn ManuallyUpdatedDate() -> Html {
/// let trigger = use_force_update();
/// let onclick = use_state(move || Callback::from(move |_| trigger.force_update()));
/// let last_update = js_sys::Date::new_0().to_utc_string();
/// html! {
/// <div>
/// <button onclick={&*onclick}>{"Update now!"}</button>
/// <p>{"Last updated: "}{last_update}</p>
/// </div>
/// }
/// }
/// ```
///
/// [`use_state`]: super::use_state()
/// [`use_reducer`]: super::use_reducer()
pub fn use_force_update() -> impl Hook<Output = UseForceUpdateHandle> {
struct UseRerenderHook;
impl Hook for UseRerenderHook {
type Output = UseForceUpdateHandle;
fn run(self, ctx: &mut HookContext) -> Self::Output {
UseForceUpdateHandle {
trigger: ctx.re_render.clone(),
}
}
}
UseRerenderHook
}
#[cfg(all(test, nightly_yew))]
mod nightly_test {
use yew::prelude::*;
#[function_component]
fn ManuallyUpdatedDate() -> Html {
let trigger = use_force_update();
let _ = move || trigger();
html! {}
}
}