pub struct Signal<T, S = UnsyncStorage>where
T: 'static,
S: Storage<SignalData<T>>,{ /* private fields */ }
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§
§impl<T> Signal<T>where
T: 'static,
impl<T> Signal<T>where
T: 'static,
pub 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.
pub 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.
pub 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.
§impl<T> Signal<T>where
T: PartialEq + 'static,
impl<T> Signal<T>where
T: PartialEq + 'static,
pub 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.
§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>>,
pub 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.
pub 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.
pub 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.
pub 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.
pub fn origin_scope(&self) -> ScopeId
pub fn origin_scope(&self) -> ScopeId
Get the scope the signal was created in.
pub fn id(&self) -> GenerationalBoxId
pub fn id(&self) -> GenerationalBoxId
Get the generational id of the signal.
pub 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§
§impl<T, S> AddAssign<T> for Signal<T, S>
impl<T, S> AddAssign<T> for Signal<T, S>
§fn add_assign(&mut self, rhs: T)
fn add_assign(&mut self, rhs: T)
+=
operation. Read more§impl<T, S> Clone for Signal<T, S>where
T: 'static,
S: Storage<SignalData<T>>,
impl<T, S> Clone for Signal<T, S>where
T: 'static,
S: Storage<SignalData<T>>,
§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
§impl<T, S> DivAssign<T> for Signal<T, S>
impl<T, S> DivAssign<T> for Signal<T, S>
§fn div_assign(&mut self, rhs: T)
fn div_assign(&mut self, rhs: T)
/=
operation. Read more§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>>,
§fn from(inner: Signal<T, S>) -> ReadOnlySignal<T, S>
fn from(inner: Signal<T, S>) -> ReadOnlySignal<T, S>
§impl<T> IntoAttributeValue for Signal<T>where
T: Clone + IntoAttributeValue,
impl<T> IntoAttributeValue for Signal<T>where
T: Clone + IntoAttributeValue,
§fn into_value(self) -> AttributeValue
fn into_value(self) -> AttributeValue
§impl<T> IntoDynNode for Signal<T>where
T: Clone + IntoDynNode,
impl<T> IntoDynNode for Signal<T>where
T: Clone + IntoDynNode,
§fn into_dyn_node(self) -> DynamicNode
fn into_dyn_node(self) -> DynamicNode
§impl<T, S> MulAssign<T> for Signal<T, S>
impl<T, S> MulAssign<T> for Signal<T, S>
§fn mul_assign(&mut self, rhs: T)
fn mul_assign(&mut self, rhs: T)
*=
operation. Read more§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>>,
§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>>,
§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.
§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>
§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>
§fn read(&self) -> <Self::Storage as AnyStorage>::Ref<'_, Self::Target>
fn read(&self) -> <Self::Storage as AnyStorage>::Ref<'_, Self::Target>
§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>
§fn read_unchecked(
&self
) -> <Self::Storage as AnyStorage>::Ref<'static, Self::Target>
fn read_unchecked( &self ) -> <Self::Storage as AnyStorage>::Ref<'static, Self::Target>
§fn peek(&self) -> <Self::Storage as AnyStorage>::Ref<'_, Self::Target>
fn peek(&self) -> <Self::Storage as AnyStorage>::Ref<'_, Self::Target>
§fn with<O>(&self, f: impl FnOnce(&Self::Target) -> O) -> O
fn with<O>(&self, f: impl FnOnce(&Self::Target) -> O) -> O
§impl<T, S> SubAssign<T> for Signal<T, S>
impl<T, S> SubAssign<T> for Signal<T, S>
§fn sub_assign(&mut self, rhs: T)
fn sub_assign(&mut self, rhs: T)
-=
operation. Read more§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>>,
§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>
§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>>
§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,
§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>
§fn write(&mut self) -> Self::Mut<'_, Self::Target>
fn write(&mut self) -> Self::Mut<'_, Self::Target>
§fn try_write(&mut self) -> Result<Self::Mut<'_, Self::Target>, BorrowMutError>
fn try_write(&mut self) -> Result<Self::Mut<'_, Self::Target>, BorrowMutError>
§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>
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>where
T: Unpin,
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
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key
and return true
if they are equal.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more§impl<T> NoneValue for Twhere
T: Default,
impl<T> NoneValue for Twhere
T: Default,
type NoneType = T
§fn null_value() -> T
fn null_value() -> T
§impl<T> Pointable for T
impl<T> Pointable for T
source§impl<R, P> ReadPrimitive<R> for P
impl<R, P> ReadPrimitive<R> for P
source§fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
ReadEndian::read_from_little_endian()
.