Skip to main content

freya_core/lifecycle/
reactive.rs

1use crate::prelude::{
2    State,
3    WritableUtils,
4    use_state,
5};
6
7/// Convert a borrowed value (`&T`) into a component-scoped [`State<T>`].
8///
9/// Useful when a component owns fields (props) and you need a reactive `State<T>` that can
10/// be passed to hooks, effects, or child components without cloning repeatedly.
11///
12/// The returned `State<T>` is initialized by cloning the provided `value`. On subsequent
13/// renders the internal state will be updated to follow `value` whenever it changes
14/// (using `PartialEq` to avoid unnecessary updates).
15///
16/// Example
17/// ```rust,no_run
18/// # use freya::prelude::*;
19/// #[derive(Clone, PartialEq)]
20/// struct Config {
21///     value: i32,
22/// }
23///
24/// #[derive(PartialEq)]
25/// struct MyComponent {
26///     config: Config,
27/// }
28///
29/// impl Component for MyComponent {
30///     fn render(&self) -> impl IntoElement {
31///         let config = use_reactive(&self.config);
32///
33///         use_side_effect(move || {
34///             // `.read()` subscribes the effect to changes of `config`
35///             let config = config.read();
36///             println!("config value: {}", config.value);
37///         });
38///
39///         rect()
40///     }
41/// }
42/// ```
43///
44/// Notes:
45/// - Call `use_reactive` at the top level of your component's `render` method like other hooks.
46/// - The hook avoids extra cloning by only setting the internal state when `value` differs.
47pub fn use_reactive<T: 'static + Clone + PartialEq>(value: &T) -> State<T> {
48    let mut state = use_state(|| value.clone());
49
50    if &*state.peek() != value {
51        state.set(value.clone());
52    }
53    state
54}