Struct freya::prelude::ReactiveContext
pub struct ReactiveContext { /* private fields */ }
Expand description
§Reactivity
The core of dioxus relies on the concept of reactivity. Reactivity is the system that updates your app when state changes.
There are two parts to reactivity: Reactive Contexts and Tracked Values.
§Reactive Contexts
Reactive Contexts keep track of what state different parts of your app rely on. Reactive Context show up throughout dioxus: Component, use_effect, use_memo and use_resource all have their own reactive contexts:
let count = use_signal(|| 0);
// The reactive context in the memo knows that the memo depends on the count signal
use_memo(move || count() * 2);
§Tracked Values
Tracked values are values that reactive contexts know about. When you read a tracked value, the reactive context will rerun when the value changes. Signals, Memos, and Resources are all tracked values:
// The count signal is tracked
let count = use_signal(|| 0);
// When you read the count signal, the reactive context subscribes to the count signal
let double_count = use_memo(move || count() * 2);
§Reactivity
Reactivity is the system that combines reactive context and tracked values to update your app when state changes.
You can use reactivity to create derived state and update your app when state changes.
You can derive state from other state with use_memo
.
use dioxus::prelude::*;
let mut count = use_signal(|| 0);
let double_count = use_memo(move || count() * 2);
// Now whenever we read double_count, we know it is always twice the value of count
println!("{}", double_count); // Prints "2"
// After we write to count, the reactive context will rerun and double_count will be updated automatically
count += 1;
println!("{}", double_count); // Prints "4"
You can also use reactivity to create derive state asynchronously. For example, you can use use_resource
to load data from a server:
use dioxus::prelude::*;
let count = use_signal(|| 0);
let double_count = use_resource(move || async move {
// Start a request to the server. We are reading the value of count to format it into the url
// Since we are reading count, this resource will "subscribe" to changes to count (when count changes, the resource will rerun)
let response = reqwest::get(format!("https://myserver.com/doubleme?count={count}")).await.unwrap();
response.text().await.unwrap()
});
§Non Reactive State
You can use plain Rust types in Dioxus, but you should be aware that they are not reactive. If you read the non-reactive state, reactive scopes will not subscribe to the state.
You can make non-reactive state reactive by using the Signal
type instead of a plain Rust type or by using the use_reactive
hook.
use dioxus::prelude::*;
// ❌ Don't create non-reactive state
let state = use_hook(|| std::cell::RefCell::new(0));
// Computed values will get out of date if the state they depend on is not reactive
let doubled = use_memo(move || *state.borrow() * 2);
// ✅ Create reactive state
let state = use_signal(|| 0);
// Computed values will automatically keep up to date with the latest reactive state
let doubled = use_memo(move || state() * 2);
// ❌ Don't depend on non-reactive prop state in memos/resources
#[component]
fn MyComponent(state: i32) -> Element {
let doubled = use_memo(move || state * 2);
todo!()
}
// ✅ Wrap your props in ReadOnlySignal to make them reactive
#[component]
fn MyReactiveComponent(state: ReadOnlySignal<i32>) -> Element {
let doubled = use_memo(move || state() * 2);
todo!()
}
If your state can’t be reactive, you can use the use_reactive
hook to make it reactive.
use dioxus::prelude::*;
let state = rand::random::<i32>();
// You can make the state reactive by wrapping it in use_reactive
let doubled = use_memo(use_reactive!(|state| state * 2));
Implementations§
§impl ReactiveContext
impl ReactiveContext
pub fn new() -> (ReactiveContext, UnboundedReceiver<()>)
pub fn new() -> (ReactiveContext, UnboundedReceiver<()>)
Create a new reactive context
pub fn new_with_origin(
origin: &'static Location<'static>
) -> (ReactiveContext, UnboundedReceiver<()>)
pub fn new_with_origin( origin: &'static Location<'static> ) -> (ReactiveContext, UnboundedReceiver<()>)
Create a new reactive context with a location for debugging purposes This is useful for reactive contexts created within closures
pub fn new_with_callback(
callback: impl FnMut() + Send + Sync + 'static,
scope: ScopeId,
origin: &'static Location<'static>
) -> ReactiveContext
pub fn new_with_callback( callback: impl FnMut() + Send + Sync + 'static, scope: ScopeId, origin: &'static Location<'static> ) -> ReactiveContext
Create a new reactive context that may update a scope. When any signal that this context subscribes to changes, the callback will be run
pub fn current() -> Option<ReactiveContext>
pub fn current() -> Option<ReactiveContext>
Get the current reactive context from the nearest reactive hook or scope
pub fn clear_subscribers(&self)
pub fn clear_subscribers(&self)
Clear all subscribers to this context
pub fn reset_and_run_in<O>(&self, f: impl FnOnce() -> O) -> O
pub fn reset_and_run_in<O>(&self, f: impl FnOnce() -> O) -> O
Reset the reactive context and then run the callback in the context. This can be used to create custom reactive hooks like use_memo
.
fn use_simplified_memo(mut closure: impl FnMut() -> i32 + 'static) -> Signal<i32> {
use_hook(|| {
// Create a new reactive context and channel that will receive a value every time a value the reactive context subscribes to changes
let (reactive_context, mut changed) = ReactiveContext::new();
// Compute the value of the memo inside the reactive context. This will subscribe the reactive context to any values you read inside the closure
let value = reactive_context.reset_and_run_in(&mut closure);
// Create a new signal with the value of the memo
let mut signal = Signal::new(value);
// Create a task that reruns the closure when the reactive context changes
spawn(async move {
while changed.next().await.is_some() {
// Since we reset the reactive context as we run the closure, our memo will only subscribe to the new values that are read in the closure
let new_value = reactive_context.run_in(&mut closure);
if new_value != value {
signal.set(new_value);
}
}
});
signal
})
}
let mut boolean = use_signal(|| false);
let mut count = use_signal(|| 0);
// Because we use `reset_and_run_in` instead of just `run_in`, our memo will only subscribe to the signals that are read this run of the closure (initially just the boolean)
let memo = use_simplified_memo(move || if boolean() { count() } else { 0 });
println!("{memo}");
// Because the count signal is not read in this run of the closure, the memo will not rerun
count += 1;
println!("{memo}");
// Because the boolean signal is read in this run of the closure, the memo will rerun
boolean.toggle();
println!("{memo}");
// If we toggle the boolean again, and the memo unsubscribes from the count signal
boolean.toggle();
println!("{memo}");
pub fn run_in<O>(&self, f: impl FnOnce() -> O) -> O
pub fn run_in<O>(&self, f: impl FnOnce() -> O) -> O
Run this function in the context of this reactive context
This will set the current reactive context to this context for the duration of the function. You can then get information about the current subscriptions.
pub fn mark_dirty(&self) -> bool
pub fn mark_dirty(&self) -> bool
Marks this reactive context as dirty
If there’s a scope associated with this context, then it will be marked as dirty too
Returns true if the context was marked as dirty, or false if the context has been dropped
pub fn subscribe(&self, subscriptions: Arc<Mutex<HashSet<ReactiveContext>>>)
pub fn subscribe(&self, subscriptions: Arc<Mutex<HashSet<ReactiveContext>>>)
Subscribe to this context. The reactive context will automatically remove itself from the subscriptions when it is reset.
pub fn origin_scope(&self) -> ScopeId
pub fn origin_scope(&self) -> ScopeId
Get the scope that inner CopyValue is associated with
Trait Implementations§
§impl Clone for ReactiveContext
impl Clone for ReactiveContext
§fn clone(&self) -> ReactiveContext
fn clone(&self) -> ReactiveContext
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more§impl Display for ReactiveContext
impl Display for ReactiveContext
§impl Hash for ReactiveContext
impl Hash for ReactiveContext
§impl PartialEq for ReactiveContext
impl PartialEq for ReactiveContext
§fn eq(&self, other: &ReactiveContext) -> bool
fn eq(&self, other: &ReactiveContext) -> bool
self
and other
values to be equal, and is used
by ==
.impl Copy for ReactiveContext
impl Eq for ReactiveContext
Auto Trait Implementations§
impl Freeze for ReactiveContext
impl !RefUnwindSafe for ReactiveContext
impl Send for ReactiveContext
impl Sync for ReactiveContext
impl Unpin for ReactiveContext
impl !UnwindSafe for ReactiveContext
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> CallHasher for T
impl<T> CallHasher for 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