State
A state is a struct with named fields.
Each field has to be wrapped in a Value
, e.g
#![allow(unused)] fn main() { name: Value<String> }
or
#![allow(unused)] fn main() { names: Value<List<String>> }
Updating state
There are two ways to update a field on State
.
state.field.set(new_value)
*state.field.to_mut() = new_value
Important note about state values
When assigning a new value to a state, do not create a new instance of
Value
This is bad:
my_state.value = Value::new(123)
This is how it should be done:
my_state.some_value.set(123);
// or
*my_state.another_value.to_mut() = 123;
External state
A component can have internal state (mutable access) and external state (read-only).
To pass external state to a component provide a map in the template with a key-value pair:
@my_comp { key: "this is a value" }
To use the external state in the component refer to the keys in the map passed into the component:
// component template
text "the value is " key
Accessing external state from a component
It's possible to access external state from within the component, using
context.external_get
.
Example
@comp { key: 123 }
#![allow(unused)] fn main() { fn on_key( &mut self, key: KeyEvent, state: &mut Self::State, mut elements: Elements<'_, '_>, mut context: Context<'_, Self::State>, ) { context.external_get("key").unwrap(); } }
Internal state
Internal state is anything that implements the State
trait.
Example
use anathema::state::{State, Value, List};
#[derive(State)]
struct MyState {
name: Value<String>,
numbers: Value<List<usize>>,
}
impl MyState {
pub fn new() -> Self {
Self {
name: String::from("Lilly").into(),
numbers: List::empty(),
}
}
}
let mut my_state = MyState::new();
my_state.numbers.push_back(1);
my_state.numbers.push_back(2);
runtime.register_component("my_comp", template, MyComponent, my_state);
Ignore fields
To store fields on the state that should be ignored by templates and widgets,
decorate the fields with #[state_ignore]
.
Example
#![allow(unused)] fn main() { #[derive(State)] struct MyState { word: Value<String>, #[state_ignore] ignored_value: usize, } }
Custom fields
Any type can be added as a field to a state as long as it implements anathema::state::State
.
The only required function to implement is fn to_common(&self) -> Option<CommonVal<'_>>
(without this the template has no way to render the value).
Types from third party crates can be wrapped using the new-type pattern.
Example
use anathema::component::*;
use anathema::state::CommonVal;
struct MyValue {
a: i64,
b: i64,
}
impl State for MyValue {
fn to_common(&self) -> Option<CommonVal<'_>> {
let total = self.a + self.b;
Some(CommonVal::Int(total))
}
}
#[derive(State)]
pub(super) struct MyState {
my_val: Value<MyValue>,
}