yew_hooks/hooks/
use_session_storage.rs

1use std::ops::Deref;
2use std::rc::Rc;
3
4use gloo::storage::{SessionStorage, Storage};
5use serde::{Deserialize, Serialize};
6use yew::prelude::*;
7
8/// State handle for the [`use_session_storage`] hook.
9pub struct UseSessionStorageHandle<T> {
10    inner: UseStateHandle<Option<T>>,
11    key: Rc<String>,
12}
13
14impl<T> UseSessionStorageHandle<T> {
15    /// Set a `value` for the specified key.
16    pub fn set(&self, value: T)
17    where
18        T: Serialize + Clone,
19    {
20        if SessionStorage::set(&*self.key, value.clone()).is_ok() {
21            self.inner.set(Some(value));
22        }
23    }
24
25    /// Delete a key and it's stored value.
26    pub fn delete(&self) {
27        SessionStorage::delete(&*self.key);
28        self.inner.set(None);
29    }
30}
31
32impl<T> Deref for UseSessionStorageHandle<T> {
33    type Target = Option<T>;
34
35    fn deref(&self) -> &Self::Target {
36        &self.inner
37    }
38}
39
40impl<T> Clone for UseSessionStorageHandle<T> {
41    fn clone(&self) -> Self {
42        Self {
43            inner: self.inner.clone(),
44            key: self.key.clone(),
45        }
46    }
47}
48
49impl<T> PartialEq for UseSessionStorageHandle<T>
50where
51    T: PartialEq,
52{
53    fn eq(&self, other: &Self) -> bool {
54        *self.inner == *other.inner
55    }
56}
57
58/// A side-effect hook that manages a single sessionStorage key.
59///
60/// # Example
61///
62/// ```rust
63/// # use yew::prelude::*;
64/// #
65/// use yew_hooks::prelude::*;
66///
67/// #[function_component(SessionStorage)]
68/// fn session_storage() -> Html {
69///     let storage = use_session_storage::<String>("foo".to_string());
70///     
71///     let onclick = {
72///         let storage = storage.clone();
73///         Callback::from(move |_| storage.set("bar".to_string()))
74///     };
75///     let ondelete = {
76///         let storage = storage.clone();
77///         Callback::from(move |_| storage.delete())
78///     };
79///
80///     html! {
81///         <div>
82///             <button onclick={onclick}>{ "Set to bar" }</button>
83///             <button onclick={ondelete}>{ "Delete" }</button>
84///             <p>
85///                 <b>{ "Current value: " }</b>
86///                 {
87///                     if let Some(value) = &*storage {
88///                         html! { value }
89///                     } else {
90///                         html! {}
91///                     }
92///                 }
93///             </p>
94///         </div>
95///     }
96/// }
97/// ```
98#[hook]
99pub fn use_session_storage<T>(key: String) -> UseSessionStorageHandle<T>
100where
101    T: for<'de> Deserialize<'de> + 'static,
102{
103    let inner: UseStateHandle<Option<T>> =
104        use_state(|| SessionStorage::get(&key).unwrap_or_default());
105    let key = use_memo((), |_| key);
106
107    UseSessionStorageHandle { inner, key }
108}