dioxus_hooks/use_signal.rs
1use dioxus_core::prelude::*;
2use dioxus_signals::{Signal, SignalData, Storage, SyncStorage, UnsyncStorage};
3
4/// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
5///
6/// ```rust
7/// use dioxus::prelude::*;
8/// use dioxus_signals::*;
9///
10/// fn App() -> Element {
11/// let mut count = use_signal(|| 0);
12///
13/// // Because signals have automatic dependency tracking, if you never read them in a component, that component will not be re-rended when the signal is updated.
14/// // The app component will never be rerendered in this example.
15/// rsx! { Child { state: count } }
16/// }
17///
18/// #[component]
19/// fn Child(state: Signal<u32>) -> Element {
20/// use_future(move || async move {
21/// // Because the signal is a Copy type, we can use it in an async block without cloning it.
22/// *state.write() += 1;
23/// });
24///
25/// rsx! {
26/// button {
27/// onclick: move |_| *state.write() += 1,
28/// "{state}"
29/// }
30/// }
31/// }
32/// ```
33///
34#[doc = include_str!("../docs/rules_of_hooks.md")]
35#[doc = include_str!("../docs/moving_state_around.md")]
36#[doc(alias = "use_state")]
37#[track_caller]
38#[must_use]
39pub fn use_signal<T: 'static>(f: impl FnOnce() -> T) -> Signal<T, UnsyncStorage> {
40 use_maybe_signal_sync(f)
41}
42
43/// Creates a new `Send + Sync`` Signal. Signals are a Copy state management solution with automatic dependency tracking.
44///
45/// ```rust
46/// use dioxus::prelude::*;
47/// use dioxus_signals::*;
48///
49/// fn App() -> Element {
50/// let mut count = use_signal_sync(|| 0);
51///
52/// // Because signals have automatic dependency tracking, if you never read them in a component, that component will not be re-rended when the signal is updated.
53/// // The app component will never be rerendered in this example.
54/// rsx! { Child { state: count } }
55/// }
56///
57/// #[component]
58/// fn Child(state: Signal<u32, SyncStorage>) -> Element {
59/// use_future(move || async move {
60/// // This signal is Send + Sync, so we can use it in an another thread
61/// tokio::spawn(async move {
62/// // Because the signal is a Copy type, we can use it in an async block without cloning it.
63/// *state.write() += 1;
64/// }).await;
65/// });
66///
67/// rsx! {
68/// button {
69/// onclick: move |_| *state.write() += 1,
70/// "{state}"
71/// }
72/// }
73/// }
74/// ```
75#[doc(alias = "use_rw")]
76#[must_use]
77#[track_caller]
78pub fn use_signal_sync<T: Send + Sync + 'static>(f: impl FnOnce() -> T) -> Signal<T, SyncStorage> {
79 use_maybe_signal_sync(f)
80}
81
82#[must_use]
83#[track_caller]
84fn use_maybe_signal_sync<T: 'static, U: Storage<SignalData<T>>>(
85 f: impl FnOnce() -> T,
86) -> Signal<T, U> {
87 let caller = std::panic::Location::caller();
88
89 // todo: (jon)
90 // By default, we want to unsubscribe the current component from the signal on every render
91 // any calls to .read() in the body will re-subscribe the component to the signal
92 // use_before_render(move || signal.unsubscribe(current_scope_id().unwrap()));
93
94 use_hook(|| Signal::new_with_caller(f(), caller))
95}