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}", value: "{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}", value: "{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 ToOnwed
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
clone!
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({
clone![val1, val2, val3];
async move {
some_work().await;
val.write().insert(1, "hello".to_string());
}
})