pub struct Signal<T, S = UnsyncStorage>where
T: 'static,
S: Storage<SignalData<T>>,{ /* private fields */ }
signals
only.Expand description
Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
use dioxus::prelude::*;
use dioxus_signals::*;
#[component]
fn App() -> Element {
let mut count = use_signal(|| 0);
// 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.
// The app component will never be rerendered in this example.
rsx! { Child { state: count } }
}
#[component]
fn Child(mut state: Signal<u32>) -> Element {
use_future(move || async move {
// Because the signal is a Copy type, we can use it in an async block without cloning it.
state += 1;
});
rsx! {
button {
onclick: move |_| state += 1,
"{state}"
}
}
}
Implementations§
source§impl<T> Signal<T>where
T: 'static,
impl<T> Signal<T>where
T: 'static,
sourcepub fn new(value: T) -> Signal<T>
pub fn new(value: T) -> Signal<T>
Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
sourcepub fn new_in_scope(value: T, owner: ScopeId) -> Signal<T>
pub fn new_in_scope(value: T, owner: ScopeId) -> Signal<T>
Create a new signal with a custom owner scope. The signal will be dropped when the owner scope is dropped instead of the current scope.
sourcepub const fn global(constructor: fn() -> T) -> GlobalSignal<T>
pub const fn global(constructor: fn() -> T) -> GlobalSignal<T>
Creates a new global Signal that can be used in a global static.
source§impl<T> Signal<T>where
T: PartialEq + 'static,
impl<T> Signal<T>where
T: PartialEq + 'static,
sourcepub const fn global_memo(constructor: fn() -> T) -> GlobalMemo<T>
pub const fn global_memo(constructor: fn() -> T) -> GlobalMemo<T>
Creates a new global Signal that can be used in a global static.
source§impl<T, S> Signal<T, S>where
T: 'static,
S: Storage<SignalData<T>>,
impl<T, S> Signal<T, S>where
T: 'static,
S: Storage<SignalData<T>>,
sourcepub fn new_maybe_sync(value: T) -> Signal<T, S>
pub fn new_maybe_sync(value: T) -> Signal<T, S>
Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
sourcepub fn new_with_caller(
value: T,
caller: &'static Location<'static>
) -> Signal<T, S>
pub fn new_with_caller( value: T, caller: &'static Location<'static> ) -> Signal<T, S>
Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
sourcepub fn new_maybe_sync_in_scope(value: T, owner: ScopeId) -> Signal<T, S>
pub fn new_maybe_sync_in_scope(value: T, owner: ScopeId) -> Signal<T, S>
Create a new signal with a custom owner scope. The signal will be dropped when the owner scope is dropped instead of the current scope.
sourcepub fn manually_drop(&self) -> Option<T>
pub fn manually_drop(&self) -> Option<T>
Drop the value out of the signal, invalidating the signal in the process.
sourcepub fn origin_scope(&self) -> ScopeId
pub fn origin_scope(&self) -> ScopeId
Get the scope the signal was created in.
sourcepub fn id(&self) -> GenerationalBoxId
pub fn id(&self) -> GenerationalBoxId
Get the generational id of the signal.
sourcepub fn write_silent(&self) -> <S as AnyStorage>::Mut<'static, T>
👎Deprecated: This pattern is no longer recommended. Prefer peek
or creating new signals instead.
pub fn write_silent(&self) -> <S as AnyStorage>::Mut<'static, T>
peek
or creating new signals instead.This pattern is no longer recommended. Prefer peek
or creating new signals instead.
This function is the equivalent of the write_silent method on use_ref.
§What you should use instead
§Reading and Writing to data in the same scope
Reading and writing to the same signal in the same scope will cause that scope to rerun forever:
let mut signal = use_signal(|| 0);
// This makes the scope rerun whenever we write to the signal
println!("{}", *signal.read());
// This will rerun the scope because we read the signal earlier in the same scope
*signal.write() += 1;
You may have used the write_silent method to avoid this infinite loop with use_ref like this:
let signal = use_signal(|| 0);
// This makes the scope rerun whenever we write to the signal
println!("{}", *signal.read());
// Write silent will not rerun any subscribers
*signal.write_silent() += 1;
Instead you can use the peek
and write
methods instead. The peek method will not subscribe to the current scope which will avoid an infinite loop if you are reading and writing to the same signal in the same scope.
let mut signal = use_signal(|| 0);
// Peek will read the value but not subscribe to the current scope
println!("{}", *signal.peek());
// Write will update any subscribers which does not include the current scope
*signal.write() += 1;
§Reading and Writing to different data
§Why is this pattern no longer recommended?
This pattern is no longer recommended because it is very easy to allow your state and UI to grow out of sync. write_silent
globally opts out of automatic state updates which can be difficult to reason about.
Lets take a look at an example: main.rs:
fn app() -> Element {
let signal = use_context_provider(|| Signal::new(0));
// We want to log the value of the signal whenever the app component reruns
println!("{}", *signal.read());
rsx! {
button {
// If we don't want to rerun the app component when the button is clicked, we can use write_silent
onclick: move |_| *signal.write_silent() += 1,
"Increment"
}
Child {}
}
}
child.rs:
fn Child() -> Element {
let signal: Signal<i32> = use_context();
// It is difficult to tell that changing the button to use write_silent in the main.rs file will cause UI to be out of sync in a completely different file
rsx! {
"{signal}"
}
}
Instead peek
locally opts out of automatic state updates explicitly for a specific read which is easier to reason about.
Here is the same example using peek: main.rs:
fn app() -> Element {
let mut signal = use_context_provider(|| Signal::new(0));
// We want to log the value of the signal whenever the app component reruns, but we don't want to rerun the app component when the signal is updated so we use peek instead of read
println!("{}", *signal.peek());
rsx! {
button {
// We can use write like normal and update the child component automatically
onclick: move |_| *signal.write() += 1,
"Increment"
}
Child {}
}
}
child.rs:
fn Child() -> Element {
let signal: Signal<i32> = use_context();
rsx! {
"{signal}"
}
}
Trait Implementations§
source§impl<T, S> AddAssign<T> for Signal<T, S>
impl<T, S> AddAssign<T> for Signal<T, S>
source§fn add_assign(&mut self, rhs: T)
fn add_assign(&mut self, rhs: T)
+=
operation. Read moresource§impl<T, S> Deref for Signal<T, S>
impl<T, S> Deref for Signal<T, S>
Allow calling a signal with signal() syntax
Currently only limited to copy types, though could probably specialize for string/arc/rc
source§impl<T, S> DivAssign<T> for Signal<T, S>
impl<T, S> DivAssign<T> for Signal<T, S>
source§fn div_assign(&mut self, rhs: T)
fn div_assign(&mut self, rhs: T)
/=
operation. Read moresource§impl<T, S> From<Signal<T, S>> for ReadOnlySignal<T, S>where
T: 'static,
S: Storage<SignalData<T>>,
impl<T, S> From<Signal<T, S>> for ReadOnlySignal<T, S>where
T: 'static,
S: Storage<SignalData<T>>,
source§fn from(inner: Signal<T, S>) -> ReadOnlySignal<T, S>
fn from(inner: Signal<T, S>) -> ReadOnlySignal<T, S>
source§impl<T> IntoAttributeValue for Signal<T>where
T: Clone + IntoAttributeValue,
impl<T> IntoAttributeValue for Signal<T>where
T: Clone + IntoAttributeValue,
source§fn into_value(self) -> AttributeValue
fn into_value(self) -> AttributeValue
source§impl<T> IntoDynNode for Signal<T>where
T: Clone + IntoDynNode,
impl<T> IntoDynNode for Signal<T>where
T: Clone + IntoDynNode,
source§fn into_dyn_node(self) -> DynamicNode
fn into_dyn_node(self) -> DynamicNode
source§impl<T, S> MulAssign<T> for Signal<T, S>
impl<T, S> MulAssign<T> for Signal<T, S>
source§fn mul_assign(&mut self, rhs: T)
fn mul_assign(&mut self, rhs: T)
*=
operation. Read moresource§impl<T, S> PartialEq for Signal<T, S>where
T: 'static,
S: Storage<SignalData<T>>,
impl<T, S> PartialEq for Signal<T, S>where
T: 'static,
S: Storage<SignalData<T>>,
source§impl<T, S> Readable for Signal<T, S>where
S: Storage<SignalData<T>>,
impl<T, S> Readable for Signal<T, S>where
S: Storage<SignalData<T>>,
source§fn peek_unchecked(
&self
) -> <<Signal<T, S> as Readable>::Storage as AnyStorage>::Ref<'static, <Signal<T, S> as Readable>::Target>
fn peek_unchecked( &self ) -> <<Signal<T, S> as Readable>::Storage as AnyStorage>::Ref<'static, <Signal<T, S> as Readable>::Target>
Get the current value of the signal. Unlike read, this will not subscribe the current scope to the signal which can cause parts of your UI to not update.
If the signal has been dropped, this will panic.
source§fn try_read_unchecked(
&self
) -> Result<<<Signal<T, S> as Readable>::Storage as AnyStorage>::Ref<'static, <Signal<T, S> as Readable>::Target>, BorrowError>
fn try_read_unchecked( &self ) -> Result<<<Signal<T, S> as Readable>::Storage as AnyStorage>::Ref<'static, <Signal<T, S> as Readable>::Target>, BorrowError>
source§fn map<O>(
self,
f: impl Fn(&Self::Target) -> &O + 'static
) -> MappedSignal<O, Self::Storage>
fn map<O>( self, f: impl Fn(&Self::Target) -> &O + 'static ) -> MappedSignal<O, Self::Storage>
source§fn read(&self) -> <Self::Storage as AnyStorage>::Ref<'_, Self::Target>
fn read(&self) -> <Self::Storage as AnyStorage>::Ref<'_, Self::Target>
source§fn try_read(
&self
) -> Result<<Self::Storage as AnyStorage>::Ref<'_, Self::Target>, BorrowError>
fn try_read( &self ) -> Result<<Self::Storage as AnyStorage>::Ref<'_, Self::Target>, BorrowError>
source§fn read_unchecked(
&self
) -> <Self::Storage as AnyStorage>::Ref<'static, Self::Target>
fn read_unchecked( &self ) -> <Self::Storage as AnyStorage>::Ref<'static, Self::Target>
source§fn peek(&self) -> <Self::Storage as AnyStorage>::Ref<'_, Self::Target>
fn peek(&self) -> <Self::Storage as AnyStorage>::Ref<'_, Self::Target>
source§fn with<O>(&self, f: impl FnOnce(&Self::Target) -> O) -> O
fn with<O>(&self, f: impl FnOnce(&Self::Target) -> O) -> O
source§impl<T, S> SubAssign<T> for Signal<T, S>
impl<T, S> SubAssign<T> for Signal<T, S>
source§fn sub_assign(&mut self, rhs: T)
fn sub_assign(&mut self, rhs: T)
-=
operation. Read moresource§impl<T, S> Writable for Signal<T, S>where
T: 'static,
S: Storage<SignalData<T>>,
impl<T, S> Writable for Signal<T, S>where
T: 'static,
S: Storage<SignalData<T>>,
source§fn map_mut<I, U, F>(
ref_: <Signal<T, S> as Writable>::Mut<'_, I>,
f: F
) -> <Signal<T, S> as Writable>::Mut<'_, U>
fn map_mut<I, U, F>( ref_: <Signal<T, S> as Writable>::Mut<'_, I>, f: F ) -> <Signal<T, S> as Writable>::Mut<'_, U>
source§fn try_map_mut<I, U, F>(
ref_: <Signal<T, S> as Writable>::Mut<'_, I>,
f: F
) -> Option<<Signal<T, S> as Writable>::Mut<'_, U>>
fn try_map_mut<I, U, F>( ref_: <Signal<T, S> as Writable>::Mut<'_, I>, f: F ) -> Option<<Signal<T, S> as Writable>::Mut<'_, U>>
source§fn downcast_lifetime_mut<'a, 'b, R>(
mut_: <Signal<T, S> as Writable>::Mut<'a, R>
) -> <Signal<T, S> as Writable>::Mut<'b, R>where
'a: 'b,
R: 'static + ?Sized,
fn downcast_lifetime_mut<'a, 'b, R>(
mut_: <Signal<T, S> as Writable>::Mut<'a, R>
) -> <Signal<T, S> as Writable>::Mut<'b, R>where
'a: 'b,
R: 'static + ?Sized,
source§fn try_write_unchecked(
&self
) -> Result<<Signal<T, S> as Writable>::Mut<'static, <Signal<T, S> as Readable>::Target>, BorrowMutError>
fn try_write_unchecked( &self ) -> Result<<Signal<T, S> as Writable>::Mut<'static, <Signal<T, S> as Readable>::Target>, BorrowMutError>
source§fn write(&mut self) -> Self::Mut<'_, Self::Target>
fn write(&mut self) -> Self::Mut<'_, Self::Target>
source§fn try_write(&mut self) -> Result<Self::Mut<'_, Self::Target>, BorrowMutError>
fn try_write(&mut self) -> Result<Self::Mut<'_, Self::Target>, BorrowMutError>
source§fn write_unchecked(&self) -> Self::Mut<'static, Self::Target>
fn write_unchecked(&self) -> Self::Mut<'static, Self::Target>
impl<T, S> Copy for Signal<T, S>where
T: 'static,
S: Storage<SignalData<T>>,
impl<T, S> Eq for Signal<T, S>where
T: 'static,
S: Storage<SignalData<T>>,
Auto Trait Implementations§
impl<T, S> Freeze for Signal<T, S>where
S: AnyStorage + Default + 'static,
impl<T, S = UnsyncStorage> !RefUnwindSafe for Signal<T, S>
impl<T, S> Send for Signal<T, S>
impl<T, S> Sync for Signal<T, S>
impl<T, S> Unpin for Signal<T, S>
impl<T, S = UnsyncStorage> !UnwindSafe for Signal<T, S>
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T, R> ReadableOptionExt<T> for R
impl<T, R> ReadableOptionExt<T> for R
source§impl<T, R> ReadableVecExt<T> for R
impl<T, R> ReadableVecExt<T> for R
source§fn first(&self) -> Option<<Self::Storage as AnyStorage>::Ref<'_, T>>
fn first(&self) -> Option<<Self::Storage as AnyStorage>::Ref<'_, T>>
source§fn last(&self) -> Option<<Self::Storage as AnyStorage>::Ref<'_, T>>
fn last(&self) -> Option<<Self::Storage as AnyStorage>::Ref<'_, T>>
source§impl<T, O> SuperFrom<T> for Owhere
O: From<T>,
impl<T, O> SuperFrom<T> for Owhere
O: From<T>,
source§fn super_from(input: T) -> O
fn super_from(input: T) -> O
source§impl<T, O, M> SuperInto<O, M> for Twhere
O: SuperFrom<T, M>,
impl<T, O, M> SuperInto<O, M> for Twhere
O: SuperFrom<T, M>,
source§fn super_into(self) -> O
fn super_into(self) -> O
source§impl<Cfg> TryIntoConfig for Cfg
impl<Cfg> TryIntoConfig for Cfg
source§fn into_config(self) -> Option<Cfg>
fn into_config(self) -> Option<Cfg>
launch
only.