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}