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}