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>implementsCopy, 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()overset()when the value might not have changed.
Implementations§
Source§impl<T: Not<Output = T> + Clone + 'static> State<T>
impl<T: Not<Output = T> + Clone + 'static> State<T>
Sourcepub fn toggled(&mut self) -> T
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§impl<T> State<T>
impl<T> State<T>
Sourcepub fn read(&self) -> ReadRef<'static, T>
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();Sourcepub fn peek(&self) -> ReadRef<'static, T>
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.
Sourcepub fn write(&mut self) -> WriteRef<'static, T>
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 mutationsset()for replacing the entire value
Sourcepub fn with_mut(&mut self, with: impl FnOnce(WriteRef<'static, T>))where
T: 'static,
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)Sourcepub fn write_unchecked(&self) -> WriteRef<'static, T>
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.
Sourcepub fn set(&mut self, value: T)where
T: 'static,
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
Sourcepub fn set_if_modified(&mut self, value: T)where
T: 'static + PartialEq,
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.
Sourcepub fn set_if_modified_and_then(&mut self, value: T, then: impl FnOnce())where
T: 'static + PartialEq,
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
Sourcepub fn create(value: T) -> Selfwhere
T: 'static,
pub fn create(value: T) -> Selfwhere
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 componentscreate_global()- For application-wide state
Sourcepub fn create_in_scope(value: T, scope_id: impl Into<Option<ScopeId>>) -> Selfwhere
T: 'static,
pub fn create_in_scope(value: T, scope_id: impl Into<Option<ScopeId>>) -> Selfwhere
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 statescope_id: The scope to attach to, orNonefor current scope
§Use Cases
- Creating state in parent scopes
- Advanced component patterns
- Testing utilities
Sourcepub fn create_global(value: T) -> Selfwhere
T: 'static,
pub fn create_global(value: T) -> Selfwhere
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>>
impl<T> State<Option<T>>
Sourcepub fn take(&mut self) -> Option<T>where
T: 'static,
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: Copy + 'static> Deref for State<T>
Allow calling the states as functions.
Limited to Copy values only.
impl<T: Copy + 'static> Deref for State<T>
Allow calling the states as functions.
Limited to Copy values only.
impl<T> Copy for State<T>
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> 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> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> ComponentProps for T
impl<T> ComponentProps for T
fn changed(&self, other: &(dyn ComponentProps + 'static)) -> bool
§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