yew_hooks/hooks/
use_map.rs

1use std::cell::{Ref, RefCell};
2use std::collections::HashMap;
3use std::hash::Hash;
4use std::rc::Rc;
5
6use yew::prelude::*;
7
8use super::use_update;
9
10/// State handle for the [`use_map`] hook.
11pub struct UseMapHandle<K, V> {
12    inner: Rc<RefCell<HashMap<K, V>>>,
13    update: Rc<dyn Fn()>,
14}
15
16impl<K, V> UseMapHandle<K, V> {
17    /// Get immutable ref to the map.
18    ///
19    /// # Panics
20    ///
21    /// Panics if the value is currently mutably borrowed
22    pub fn current(&self) -> Ref<HashMap<K, V>> {
23        self.inner.borrow()
24    }
25
26    /// Set the hash map.
27    pub fn set(&self, map: HashMap<K, V>) {
28        *self.inner.borrow_mut() = map;
29        (self.update)();
30    }
31
32    /// Inserts a key-value pair into the map.
33    pub fn insert(&self, k: K, v: V) -> Option<V>
34    where
35        K: Eq + Hash,
36    {
37        let v = self.inner.borrow_mut().insert(k, v);
38        (self.update)();
39        v
40    }
41
42    /// Update key-value pair.
43    pub fn update(&self, k: &K, v: V)
44    where
45        K: Eq + Hash,
46    {
47        if let Some(value) = self.inner.borrow_mut().get_mut(k) {
48            *value = v;
49        }
50        (self.update)();
51    }
52
53    /// Removes a key from the map, returning the value at the key if the key was previously in the map.
54    pub fn remove(&self, k: &K) -> Option<V>
55    where
56        K: Eq + Hash,
57    {
58        let v = self.inner.borrow_mut().remove(k);
59        (self.update)();
60        v
61    }
62
63    /// Retains only the elements specified by the predicate.
64    pub fn retain<F>(&self, f: F)
65    where
66        K: Eq + Hash,
67        F: FnMut(&K, &mut V) -> bool,
68    {
69        self.inner.borrow_mut().retain(f);
70        (self.update)();
71    }
72
73    /// Clears the map, removing all key-value pairs. Keeps the allocated memory for reuse.
74    pub fn clear(&self) {
75        self.inner.borrow_mut().clear();
76        (self.update)();
77    }
78}
79
80impl<K, V> Clone for UseMapHandle<K, V> {
81    fn clone(&self) -> Self {
82        Self {
83            inner: self.inner.clone(),
84            update: self.update.clone(),
85        }
86    }
87}
88
89impl<K, V> PartialEq for UseMapHandle<K, V>
90where
91    K: Eq + Hash,
92    V: PartialEq,
93{
94    fn eq(&self, other: &Self) -> bool {
95        *self.inner == *other.inner
96    }
97}
98
99/// A hook that tracks a hash map and provides methods to modify it.
100///
101/// # Example
102///
103/// ```rust
104/// # use std::collections::HashMap;
105/// # use yew::prelude::*;
106/// #
107/// use yew_hooks::prelude::*;
108///
109/// #[function_component(UseMap)]
110/// fn map() -> Html {
111///     let map = use_map(HashMap::from([
112///         ("Mercury", 0.4),
113///         ("Venus", 0.7),
114///         ("Earth", 1.0),
115///         ("Mars", 1.5),
116///     ]));
117///
118///     let onset = {
119///         let map = map.clone();
120///         Callback::from(move |_| map.set(HashMap::from([("Moon", 0.8), ("Earth", 1.0)])))
121///     };
122///     let oninsert = {
123///         let map = map.clone();
124///         Callback::from(move |_| {
125///             let _ = map.insert("Jupiter", 2.1);
126///         })
127///     };
128///     let onupdate = {
129///         let map = map.clone();
130///         Callback::from(move |_| map.update(&"Earth", 1.1))
131///     };
132///     let onremove = {
133///         let map = map.clone();
134///         Callback::from(move |_| {
135///             let _ = map.remove(&"Moon");
136///         })
137///     };
138///     let onretain = {
139///         let map = map.clone();
140///         Callback::from(move |_| map.retain(|_k, v| v > &mut 1.0))
141///     };
142///     let onclear = {
143///         let map = map.clone();
144///         Callback::from(move |_| map.clear())
145///     };
146///
147///     html! {
148///         <div>
149///             <button onclick={onset}>{ "Set" }</button>
150///             <button onclick={oninsert}>{ "Insert" }</button>
151///             <button onclick={onupdate}>{ "Update" }</button>
152///             <button onclick={onremove}>{ "Remove" }</button>
153///             <button onclick={onretain}>{ "Retain" }</button>
154///             <button onclick={onclear}>{ "Clear all" }</button>
155///             <p>
156///                 <b>{ "Current value: " }</b>
157///             </p>
158///             {
159///                 for map.current().iter().map(|(k, v)| {
160///                     html! {
161///                         <p><b>{ k }</b> {": "} { v }</p>
162///                     }
163///                 })
164///             }
165///         </div>
166///     }
167/// }
168/// ```
169#[hook]
170pub fn use_map<K, V>(initial_value: HashMap<K, V>) -> UseMapHandle<K, V>
171where
172    K: 'static,
173    V: 'static,
174{
175    let inner = use_mut_ref(|| initial_value);
176    let update = use_update();
177
178    UseMapHandle { inner, update }
179}