dioxus_lib::prelude

Struct ReactiveContext

source
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§

source§

impl ReactiveContext

source

pub fn new() -> (ReactiveContext, UnboundedReceiver<()>)

Create a new reactive context

source

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

source

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

source

pub fn current() -> Option<ReactiveContext>

Get the current reactive context from the nearest reactive hook or scope

source

pub fn clear_subscribers(&self)

Clear all subscribers to this context

source

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}");
source

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.

source

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

source

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.

source

pub fn origin_scope(&self) -> ScopeId

Get the scope that inner CopyValue is associated with

Trait Implementations§

source§

impl Clone for ReactiveContext

source§

fn clone(&self) -> ReactiveContext

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Display for ReactiveContext

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
source§

impl Hash for ReactiveContext

source§

fn hash<H>(&self, state: &mut H)
where H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl PartialEq for ReactiveContext

source§

fn eq(&self, other: &ReactiveContext) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl Copy for ReactiveContext

source§

impl Eq for ReactiveContext

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where T: Clone,

source§

unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> InitializeFromFunction<T> for T

source§

fn initialize_from_function(f: fn() -> T) -> T

Create an instance of this type from an initialization function
source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<Ret> SpawnIfAsync<(), Ret> for Ret

source§

fn spawn(self) -> Ret

Spawn the value into the dioxus runtime if it is an async block
source§

impl<T, O> SuperFrom<T> for O
where O: From<T>,

source§

fn super_from(input: T) -> O

Convert from a type to another type.
source§

impl<T, O, M> SuperInto<O, M> for T
where O: SuperFrom<T, M>,

source§

fn super_into(self) -> O

Convert from a type to another type.
source§

impl<T> ToOwned for T
where T: Clone,

source§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T> ToString for T
where T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

source§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

impl<T> DependencyElement for T
where T: 'static + PartialEq + Clone,