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
use crate::context::ContextHandle;
use crate::functional::{get_current_scope, use_hook};
/// Hook for consuming context values in function components.
/// The context of the type passed as `T` is returned. If there is no such context in scope, `None` is returned.
/// A component which calls `use_context` will re-render when the data of the context changes.
///
/// More information about contexts and how to define and consume them can be found on [Yew Docs](https://yew.rs).
///
/// # Example
/// ```rust
/// # use yew::prelude::*;
/// # use std::rc::Rc;
///
/// # #[derive(Clone, Debug, PartialEq)]
/// # struct ThemeContext {
/// # foreground: String,
/// # background: String,
/// # }
/// #[function_component(ThemedButton)]
/// pub fn themed_button() -> Html {
/// let theme = use_context::<Rc<ThemeContext>>().expect("no ctx found");
///
/// html! {
/// <button style={format!("background: {}; color: {}", theme.background, theme.foreground)}>
/// { "Click me" }
/// </button>
/// }
/// }
/// ```
pub fn use_context<T: Clone + PartialEq + 'static>() -> Option<T> {
struct UseContextState<T2: Clone + PartialEq + 'static> {
initialized: bool,
context: Option<(T2, ContextHandle<T2>)>,
}
let scope = get_current_scope()
.expect("No current Scope. `use_context` can only be called inside function components");
use_hook(
move || UseContextState {
initialized: false,
context: None,
},
|state: &mut UseContextState<T>, updater| {
if !state.initialized {
state.initialized = true;
let callback = move |ctx: T| {
updater.callback(|state: &mut UseContextState<T>| {
if let Some(context) = &mut state.context {
context.0 = ctx;
}
true
});
};
state.context = scope.context::<T>(callback.into());
}
Some(state.context.as_ref()?.0.clone())
},
|state| {
state.context = None;
},
)
}