State

Struct State 

Source
pub struct State<T> { /* private fields */ }
Expand description

A reactive state container that holds a value of type T and manages subscriptions to changes.

State<T> is the fundamental reactive primitive in Freya. It allows you to store mutable state that automatically triggers re-renders in components that read from it when the value changes.

§Key Features

  • Reactive: Components automatically re-render when the state value changes.
  • Copy: State<T> implements Copy, making it cheap to pass around.
  • Shared: Multiple components can read from and write to the same state.
  • Scoped: State is automatically cleaned up when its owning component unmounts.

§Basic Usage

use freya::prelude::*;

fn counter() -> impl IntoElement {
    // Create reactive state
    let mut count = use_state(|| 0);

    rect().child(format!("Count: {}", count.read())).child(
        Button::new()
            .child("Increment")
            .on_press(move |_| *count.write() += 1),
    )
}

§Reading State

  • state.read() - Reads the current value and subscribes the current component to changes.
  • state.peek() - Reads the current value without subscribing (rarely needed).

§Writing State

  • state.write() - Gets a mutable reference to modify the value.
  • state.set(new_value) - Replaces the current value.
  • state.with_mut(|mut_ref| { /* modify */ }) - Modifies using a closure.

§Advanced Patterns

§Conditional Updates

let mut count = use_state(|| 0);

// Only update if the new value is different
count.set_if_modified(5);

// Update and run additional logic
count.set_if_modified_and_then(10, || {
    println!("Count reached 10!");
});

§Working with Options

let mut optional_value = use_state(|| Some(42));

// Take ownership of the contained value
let taken_value = optional_value.take(); // Returns Option<i32>

§Copy Types

For Copy types, you can call the state as a function to read:

let count = use_state(|| 0);

// These are equivalent:
let value1 = count.read().clone();
let value2 = count(); // Only works for Copy types

§Global State

For state that persists across the entire application lifecycle:

// Create global state (use sparingly)
let global_count = State::create_global(0);

§Thread Safety

State<T> is not thread-safe and should only be used within the main UI thread. For cross-thread communication, consider using channels or other synchronization primitives.

§Performance Notes

  • Reading state subscribes the current component, causing re-renders when it changes.
  • Use peek() only when you specifically don’t want reactivity.
  • Prefer set_if_modified() over set() when the value might not have changed.

Implementations§

Source§

impl<T: Not<Output = T> + Clone + 'static> State<T>

Source

pub fn toggled(&mut self) -> T

Toggle the boolean-like value and return the new value.

This method negates the current value using the ! operator and returns the new value after updating the state.

§Requirements

The type T must implement std::ops::Not<Output = T> + Clone.

§Example
let mut flag = use_state(|| false);

// Toggle and get the new value
let new_value = flag.toggled(); // false -> true, returns true
assert_eq!(new_value, true);
§Common Types

Works with bool, custom enum types, etc.

Source

pub fn toggle(&mut self)

Toggle the boolean-like value without returning it.

This is a convenience method that toggles the value but discards the result. Equivalent to calling toggled and ignoring the return value.

§Example
let mut is_visible = use_state(|| false);

// Toggle visibility
is_visible.toggle(); // false -> true
Source§

impl<T> State<T>

Source

pub fn read(&self) -> ReadRef<'static, T>

Read the current value and subscribe the current component to changes.

When the state value changes, any component or hook that has called read() will re-render.

§Example
let count = use_state(|| 0);
let current_value = count.read();
Source

pub fn peek(&self) -> ReadRef<'static, T>

Read the current value without subscribing to changes.

This method provides access to the current state value without registering the current component as a subscriber. The component will not re-render if the state changes.

§When to Use

Use peek() when you need to read the state value for a one-off operation where reactivity is not needed, such as:

  • Comparisons for conditional updates
  • Debugging/logging
  • Initial value checks
§Example
let count = use_state(|| 0);

// Check if count is zero without subscribing
if *count.peek() == 0 {
    println!("Count is still zero");
}

// For reactive reading, use `read()` instead:
let display_text = format!("Count: {}", count.read());
§Performance Note

Prefer read() over peek() unless you specifically need non-reactive access.

Source

pub fn write(&mut self) -> WriteRef<'static, T>

Get a mutable reference to the state value and notify subscribers.

This method returns a WriteRef<T> that allows direct mutation of the state value. All subscribed components will be notified and will re-render on the next frame.

§Example
let mut count = use_state(|| 0);

// Direct mutation
*count.write() += 1;

// Multiple operations
{
    let mut value = count.write();
    *value *= 2;
    *value += 10;
} // Subscribers notified here
§See Also
  • with_mut() for closure-based mutations
  • set() for replacing the entire value
Source

pub fn with_mut(&mut self, with: impl FnOnce(WriteRef<'static, T>))
where T: 'static,

Modify the state value using a closure and notify subscribers.

This method provides a convenient way to mutate the state value using a closure, automatically handling subscriber notification.

§Example
let mut counter = use_state(|| 0);

counter.with_mut(|mut value| {
    *value += 1;
    *value *= 2;
});

// Equivalent to:
*counter.write() += 1;
*counter.write() *= 2;
// But more efficient (single notification)
Source

pub fn write_unchecked(&self) -> WriteRef<'static, T>

Get a mutable reference without requiring a mutable borrow of the State.

This is an advanced method that allows writing to the state without having mutable access to the State itself. Use with caution as it bypasses Rust’s borrow checker guarantees.

§Safety Considerations

This method should only be used when you cannot obtain a mutable reference to the State but still need to modify it. Prefer write() when possible.

Source

pub fn set(&mut self, value: T)
where T: 'static,

Replace the current state value with a new one.

This method completely replaces the existing value with the provided one and notifies all subscribers.

§Example
let mut status = use_state(|| "idle");

// Replace the value
status.set("loading");
status.set("complete");
§See Also
  • set_if_modified() to avoid unnecessary updates when the value hasn’t changed
Source

pub fn set_if_modified(&mut self, value: T)
where T: 'static + PartialEq,

Replace the state value only if it’s different from the current value.

This method compares the new value with the current value using PartialEq. If they are different, it updates the state and notifies subscribers. If they are the same, no update occurs.

§Performance Benefits

This prevents unnecessary re-renders when setting the same value repeatedly.

§Example
let mut count = use_state(|| 0);

// This will update and notify subscribers
count.set_if_modified(5);

// This will do nothing (value is already 5)
count.set_if_modified(5);
§Requirements

The type T must implement PartialEq.

Source

pub fn set_if_modified_and_then(&mut self, value: T, then: impl FnOnce())
where T: 'static + PartialEq,

Replace the state value if modified and execute a callback.

Similar to set_if_modified(), but also runs a callback function if the value was actually changed.

§Example
let mut score = use_state(|| 0);

score.set_if_modified_and_then(100, || {
    println!("High score achieved!");
    // Trigger additional logic like saving to storage
});
§Use Cases
  • Logging state changes
  • Triggering side effects only when value changes
  • Analytics tracking
Source

pub fn create(value: T) -> Self
where T: 'static,

Create a new State attached to the current component’s scope.

This method creates a reactive state value that will be automatically cleaned up when the current component unmounts.

§Example
// Usually used through use_state() hook instead:
let count = use_state(|| 0);

// Direct creation (rare):
let state = State::create(42);
§See Also
  • use_state() - The recommended way to create state in components
  • create_global() - For application-wide state
Source

pub fn create_in_scope(value: T, scope_id: impl Into<Option<ScopeId>>) -> Self
where T: 'static,

Create a State attached to a specific scope.

Advanced method for creating state in a different scope than the current one. Pass None to attach to the current scope (same as create()).

§Parameters
  • value: The initial value for the state
  • scope_id: The scope to attach to, or None for current scope
§Use Cases
  • Creating state in parent scopes
  • Advanced component patterns
  • Testing utilities
Source

pub fn create_global(value: T) -> Self
where T: 'static,

Create a global State that persists for the entire application lifetime.

This creates state that is not tied to any component scope and will live until the application shuts down. Use sparingly as it can lead to memory leaks if not managed carefully.

§Warning

Global state should be used judiciously. Prefer component-scoped state (use_state()) or shared state (freya-radio) for most use cases.

§Example
// Create global state in a function
fn create_global_config() -> State<i32> {
    State::create_global(42)
}
§Memory Management

Global state is leaked using Box::leak() and will not be automatically cleaned up. Ensure global state contains lightweight data or implement manual cleanup if needed.

Source§

impl<T> State<Option<T>>

Source

pub fn take(&mut self) -> Option<T>
where T: 'static,

Take ownership of the contained value, leaving None in its place.

This method is only available for State<Option<T>> and moves the value out of the state, replacing it with None.

§Example
let mut maybe_value = use_state(|| Some("hello".to_string()));

// Take the value, state becomes None
let taken = maybe_value.take(); // Some("hello")
assert_eq!(*maybe_value.read(), None);
§Use Cases
  • Moving values out of reactive state
  • One-time consumption of optional state
  • State transitions where the value is no longer needed

Trait Implementations§

Source§

impl<T> Clone for State<T>

Source§

fn clone(&self) -> Self

Returns a duplicate 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<T: Copy + 'static> Deref for State<T>

Allow calling the states as functions. Limited to Copy values only.

Source§

type Target = dyn Fn() -> T

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.
Source§

impl<T> From<State<T>> for ReadState<T>

Source§

fn from(value: State<T>) -> Self

Converts to this type from the input type.
Source§

impl<T: 'static> MutView<'static, T> for State<T>

Source§

fn read(&mut self) -> ReadRef<'static, T>

Source§

fn peek(&mut self) -> ReadRef<'static, T>

Source§

fn write(&mut self) -> WriteRef<'static, T>

Source§

fn write_if(&mut self, with: impl FnOnce(WriteRef<'static, T>) -> bool)

Source§

impl<T: 'static> PartialEq for State<T>

Source§

fn eq(&self, other: &Self) -> 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<T> Copy for State<T>

Source§

impl<T: 'static> Eq for State<T>

Auto Trait Implementations§

§

impl<T> Freeze for State<T>

§

impl<T> !RefUnwindSafe for State<T>

§

impl<T> !Send for State<T>

§

impl<T> !Sync for State<T>

§

impl<T> Unpin for State<T>
where T: Unpin,

§

impl<T> !UnwindSafe for State<T>

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, dest: *mut u8)

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

impl<T> ComponentProps for T
where T: Any + PartialEq,

Source§

fn changed(&self, other: &(dyn ComponentProps + 'static)) -> bool

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

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

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

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<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
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, 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.
§

impl<T> WithSubscriber for T

§

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
§

fn with_current_subscriber(self) -> WithDispatch<Self>

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