This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

yew/functional/hooks/
use_context.rs

1use std::cell::RefCell;
2use std::marker::PhantomData;
3use std::rc::Rc;
4
5use crate::callback::Callback;
6use crate::context::ContextHandle;
7use crate::functional::{Hook, HookContext};
8
9/// Hook for consuming context values in function components.
10/// The context of the type passed as `T` is returned. If there is no such context in scope, `None`
11/// is returned. A component which calls `use_context` will re-render when the data of the context
12/// changes.
13///
14/// More information about contexts and how to define and consume them can be found on [Yew Docs](https://yew.rs/docs/concepts/contexts).
15///
16/// # Example
17///
18/// ```rust
19/// use yew::{ContextProvider, function_component, html, use_context, use_state, Html};
20///
21///
22/// /// App theme
23/// #[derive(Clone, Debug, PartialEq)]
24/// struct Theme {
25///     foreground: String,
26///     background: String,
27/// }
28///
29/// /// Main component
30/// #[function_component]
31/// pub fn App() -> Html {
32///     let ctx = use_state(|| Theme {
33///         foreground: "#000000".to_owned(),
34///         background: "#eeeeee".to_owned(),
35///     });
36///
37///     html! {
38///         // `ctx` is type `Rc<UseStateHandle<Theme>>` while we need `Theme`
39///         // so we deref it.
40///         // It derefs to `&Theme`, hence the clone
41///         <ContextProvider<Theme> context={(*ctx).clone()}>
42///             // Every child here and their children will have access to this context.
43///             <Toolbar />
44///         </ContextProvider<Theme>>
45///     }
46/// }
47///
48/// /// The toolbar.
49/// /// This component has access to the context
50/// #[function_component]
51/// pub fn Toolbar() -> Html {
52///     html! {
53///         <div>
54///             <ThemedButton />
55///         </div>
56///     }
57/// }
58///
59/// /// Button placed in `Toolbar`.
60/// /// As this component is a child of `ThemeContextProvider` in the component tree, it also has access to the context.
61/// #[function_component]
62/// pub fn ThemedButton() -> Html {
63///     let theme = use_context::<Theme>().expect("no ctx found");
64///
65///     html! {
66///         <button style={format!("background: {}; color: {};", theme.background, theme.foreground)}>
67///             { "Click me!" }
68///         </button>
69///     }
70/// }
71/// ```
72pub fn use_context<T: Clone + PartialEq + 'static>() -> impl Hook<Output = Option<T>> {
73    struct HookProvider<T: Clone + PartialEq + 'static> {
74        _marker: PhantomData<T>,
75    }
76
77    struct UseContext<T: Clone + PartialEq + 'static> {
78        _handle: Option<ContextHandle<T>>,
79        value: Rc<RefCell<Option<T>>>,
80    }
81
82    impl<T> Hook for HookProvider<T>
83    where
84        T: Clone + PartialEq + 'static,
85    {
86        type Output = Option<T>;
87
88        fn run(self, ctx: &mut HookContext) -> Self::Output {
89            let scope = ctx.scope.clone();
90
91            let state = ctx.next_state(move |re_render| -> UseContext<T> {
92                let value_cell: Rc<RefCell<Option<T>>> = Rc::default();
93
94                let (init_value, handle) = {
95                    let value_cell = value_cell.clone();
96
97                    scope.context(Callback::from(move |m| {
98                        *(value_cell.borrow_mut()) = Some(m);
99                        re_render()
100                    }))
101                }
102                .map(|(value, handle)| (Some(value), Some(handle)))
103                .unwrap_or((None, None));
104
105                *(value_cell.borrow_mut()) = init_value;
106
107                UseContext {
108                    _handle: handle,
109                    value: value_cell,
110                }
111            });
112
113            let value = state.value.borrow();
114            value.clone()
115        }
116    }
117
118    HookProvider {
119        _marker: PhantomData,
120    }
121}