yew_hooks/hooks/use_list.rs
1use std::cell::{Ref, RefCell};
2use std::cmp::Ordering;
3use std::rc::Rc;
4
5use yew::prelude::*;
6
7use super::use_update;
8
9/// State handle for the [`use_list`] hook.
10pub struct UseListHandle<T> {
11 inner: Rc<RefCell<Vec<T>>>,
12 update: Rc<dyn Fn()>,
13}
14
15impl<T> UseListHandle<T> {
16 /// Get immutable ref to the list.
17 ///
18 /// # Panics
19 ///
20 /// Panics if the value is currently mutably borrowed
21 pub fn current(&self) -> Ref<Vec<T>> {
22 self.inner.borrow()
23 }
24
25 /// Set the list by `elements`
26 pub fn set(&self, elements: Vec<T>) {
27 *self.inner.borrow_mut() = elements;
28 (self.update)();
29 }
30
31 /// Insert an element at the specified index
32 ///
33 /// # Panics
34 ///
35 /// Panics if `index` > `len`.
36 pub fn insert(&self, index: usize, element: T) {
37 self.inner.borrow_mut().insert(index, element);
38 (self.update)();
39 }
40
41 /// Update the element at the specified index
42 pub fn update(&self, index: usize, element: T) {
43 if let Some(elem) = self.inner.borrow_mut().get_mut(index) {
44 *elem = element;
45 }
46 (self.update)();
47 }
48
49 /// Removes and returns the element at position index within the list,
50 /// shifting all elements after it to the left.
51 ///
52 /// # Panics
53 ///
54 /// Panics if index is out of bounds.
55 pub fn remove(&self, index: usize) -> T {
56 let elem = self.inner.borrow_mut().remove(index);
57 (self.update)();
58 elem
59 }
60
61 /// Appends an element to the back of a collection.
62 pub fn push(&self, value: T) {
63 self.inner.borrow_mut().push(value);
64 (self.update)();
65 }
66
67 /// Removes the last element from a vector and returns it, or None if it is empty.
68 pub fn pop(&self) -> Option<T> {
69 let value = self.inner.borrow_mut().pop();
70 (self.update)();
71 value
72 }
73
74 /// Retains only the elements specified by the predicate.
75 pub fn retain<F>(&self, f: F)
76 where
77 F: FnMut(&T) -> bool,
78 {
79 self.inner.borrow_mut().retain(f);
80 (self.update)();
81 }
82
83 /// Reverses the order of elements in the slice, in place.
84 pub fn reverse(&self) {
85 self.inner.borrow_mut().reverse();
86 (self.update)();
87 }
88
89 /// Moves all the elements of other into Self, leaving other empty.
90 pub fn append(&self, other: &mut Vec<T>) {
91 self.inner.borrow_mut().append(other);
92 (self.update)();
93 }
94
95 /// Sorts the list.
96 pub fn sort(&self)
97 where
98 T: Ord,
99 {
100 self.inner.borrow_mut().sort();
101 (self.update)();
102 }
103
104 /// Sorts the list with a comparator function.
105 pub fn sort_by<F>(&self, compare: F)
106 where
107 F: FnMut(&T, &T) -> Ordering,
108 {
109 self.inner.borrow_mut().sort_by(compare);
110 (self.update)();
111 }
112
113 /// Swaps two elements in the list.
114 pub fn swap(&self, a: usize, b: usize) {
115 self.inner.borrow_mut().swap(a, b);
116 (self.update)();
117 }
118
119 /// Clears the list, removing all values.
120 pub fn clear(&self) {
121 self.inner.borrow_mut().clear();
122 (self.update)();
123 }
124}
125
126impl<T> Clone for UseListHandle<T> {
127 fn clone(&self) -> Self {
128 Self {
129 inner: self.inner.clone(),
130 update: self.update.clone(),
131 }
132 }
133}
134
135impl<T> PartialEq for UseListHandle<T>
136where
137 T: PartialEq,
138{
139 fn eq(&self, other: &Self) -> bool {
140 *self.inner == *other.inner
141 }
142}
143
144/// A hook that tracks a list and provides methods to modify it.
145///
146/// # Example
147///
148/// ```rust
149/// # use yew::prelude::*;
150/// #
151/// use yew_hooks::prelude::*;
152///
153/// #[function_component(UseList)]
154/// fn list() -> Html {
155/// let list = use_list(vec![1, 2, 3, 4, 5]);
156///
157/// let onset = {
158/// let list = list.clone();
159/// Callback::from(move |_| list.set(vec![6, 7, 8, 9, 10]))
160/// };
161/// let oninsert = {
162/// let list = list.clone();
163/// Callback::from(move |_| list.insert(0, 9))
164/// };
165/// let onupdate = {
166/// let list = list.clone();
167/// Callback::from(move |_| list.update(0, 4))
168/// };
169/// let onremove = {
170/// let list = list.clone();
171/// Callback::from(move |_| { let _ = list.remove(0); })
172/// };
173/// let onretain = {
174/// let list = list.clone();
175/// Callback::from(move |_| list.retain(|x| x % 2 == 0))
176/// };
177/// let onclear = {
178/// let list = list.clone();
179/// Callback::from(move |_| list.clear())
180/// };
181///
182/// html! {
183/// <div>
184/// <button onclick={onset}>{ "Set to [6, 7, 8, 9, 10]" }</button>
185/// <button onclick={oninsert}>{ "Insert 9 at position 0" }</button>
186/// <button onclick={onupdate}>{ "Update to 4 at position 0" }</button>
187/// <button onclick={onremove}>{ "Remove position 0" }</button>
188/// <button onclick={onretain}>{ "Retain even numbers" }</button>
189/// <button onclick={onclear}>{ "Clear all" }</button>
190/// <p>
191/// <b>{ "Current value: " }</b>
192/// {
193/// for list.current().iter().map(|element| {
194/// html! { element }
195/// })
196/// }
197/// </p>
198/// </div>
199/// }
200/// }
201/// ```
202#[hook]
203pub fn use_list<T>(initial_value: Vec<T>) -> UseListHandle<T>
204where
205 T: 'static,
206{
207 let inner = use_mut_ref(|| initial_value);
208 let update = use_update();
209
210 UseListHandle { inner, update }
211}