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