pub fn use_ref<T>(
cx: &ScopeState,
initialize_refcell: impl FnOnce() -> T
) -> &UseRef<T>where
T: 'static,Expand description
use_ref is a key foundational hook for storing state in Dioxus.
It is different that use_state in that the value stored is not “immutable”.
Instead, UseRef is designed to store larger values that will be mutated at will.
Writing Values
Generally, use_ref is just a wrapper around a RefCell that tracks mutable
writes through the write method. Whenever write is called, the component
that initialized the hook will be marked as “dirty”.
let val = use_ref(|| HashMap::<u32, String>::new());
// using `write` will give us a `RefMut` to the inner value, which we can call methods on
// This marks the component as "dirty"
val.write().insert(1, "hello".to_string());You can avoid this default behavior with write_silent
// with `write_silent`, the component will not be re-rendered
val.write_silent().insert(2, "goodbye".to_string());Reading Values
To read values out of the refcell, you can use the read method which will retrun a Ref.
let map: Ref<_> = val.read();
let item = map.get(&1);To get an &T out of the RefCell, you need to “reborrow” through the Ref:
let read = val.read();
let map = &*read;Collections and iteration
A common usecase for use_ref is to store a large amount of data in a component.
Typically this will be a collection like a HashMap or a Vec. To create new
elements from the collection, we can use read() directly in our rsx!.
rsx!{
val.read().iter().map(|(k, v)| {
rsx!{ key: "{k}", "{v}" }
})
}If you are generating elements outside of rsx! then you might need to call
“render” inside the iterator. For some cases you might need to collect into
a temporary Vec.
let items = val.read().iter().map(|(k, v)| {
cx.render(rsx!{ key: "{k}", "{v}" })
});
// collect into a Vec
let items: Vec<Element> = items.collect();Use in Async
To access values from a UseRef in an async context, you need to detach it
from the current scope’s lifetime, making it a 'static value. This is done
by simply calling to_owned or clone.
let val = use_ref(|| HashMap::<u32, String>::new());
cx.spawn({
let val = val.clone();
async move {
some_work().await;
val.write().insert(1, "hello".to_string());
}
})If you’re working with lots of values like UseState and UseRef, you can use the
to_owned! macro to make it easier to write the above code.
let val1 = use_ref(|| HashMap::<u32, String>::new());
let val2 = use_ref(|| HashMap::<u32, String>::new());
let val3 = use_ref(|| HashMap::<u32, String>::new());
cx.spawn({
to_owned![val1, val2, val3];
async move {
some_work().await;
val.write().insert(1, "hello".to_string());
}
})