pub fn use_storage<T, C>(
storage_type: StorageType,
key: impl AsRef<str>,
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
Expand description
Reactive Storage.
The function returns a triplet (read_signal, write_signal, delete_from_storage_fn)
.
§Demo
§Usage
Pass a StorageType
to determine the kind of key-value browser storage to use.
The specified key is where data is stored. All values are stored as UTF-16 strings which
is then encoded and decoded via the given *Codec
. This value is synced with other calls using
the same key on the same page and across tabs for local storage.
See UseStorageOptions
to see how behavior can be further customised.
Values are (en)decoded via the given codec. You can use any of the string codecs or a
binary codec wrapped in Base64
.
Please check the codec chapter to see what codecs are available and what feature flags they require.
§Example
// Binds a struct:
let (state, set_state, _) = use_local_storage::<MyState, JsonSerdeCodec>("my-state");
// Binds a bool, stored as a string:
let (flag, set_flag, remove_flag) = use_session_storage::<bool, FromToStringCodec>("my-flag");
// Binds a number, stored as a string:
let (count, set_count, _) = use_session_storage::<i32, FromToStringCodec>("my-count");
// Binds a number, stored in JSON:
let (count, set_count, _) = use_session_storage::<i32, JsonSerdeCodec>("my-count-kept-in-js");
// Bind string with SessionStorage stored in ProtoBuf format:
let (id, set_id, _) = use_storage::<String, Base64<ProstCodec>>(
StorageType::Session,
"my-id",
);
// Data stored in JSON must implement Serialize, Deserialize.
// And you have to add the feature "serde" to your project's Cargo.toml
#[derive(Serialize, Deserialize, Clone, PartialEq)]
pub struct MyState {
pub hello: String,
pub greeting: String,
}
// Default can be used to implement initial or deleted values.
// You can also use a signal via UseStorageOptions::default_value`
impl Default for MyState {
fn default() -> Self {
Self {
hello: "hi".to_string(),
greeting: "Hello".to_string()
}
}
}
§Server-Side Rendering
On the server the returned signals will just read/manipulate the initial_value
without persistence.
§Hydration bugs and use_cookie
If you use a value from storage to control conditional rendering you might run into issues with hydration.
let (flag, set_flag, _) = use_session_storage::<bool, FromToStringCodec>("my-flag");
view! {
<Show when=move || flag.get()>
<div>Some conditional content</div>
</Show>
}
You can see hydration warnings in the browser console and the conditional parts of
the app might never show up when rendered on the server and then hydrated in the browser. The
reason for this is that the server has no access to storage and therefore will always use
initial_value
as described above. So on the server your app is always rendered as if
the value from storage was initial_value
. Then in the browser the actual stored value is used
which might be different, hence during hydration the DOM looks different from the one rendered
on the server which produces the hydration warnings.
The recommended way to avoid this is to use use_cookie
instead because values stored in cookies
are available on the server as well as in the browser.
If you still want to use storage instead of cookies you can use the delay_during_hydration
option that will use the initial_value
during hydration just as on the server and delay loading
the value from storage by an animation frame. This gets rid of the hydration warnings and makes
the app correctly render things. Some flickering might be unavoidable though.
let (flag, set_flag, _) = use_local_storage_with_options::<bool, FromToStringCodec>(
"my-flag",
UseStorageOptions::default().delay_during_hydration(true),
);
view! {
<Show when=move || flag.get()>
<div>Some conditional content</div>
</Show>
}