usestate.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. #![warn(clippy::pedantic)]
  2. use dioxus_core::prelude::*;
  3. use std::{
  4. cell::{RefCell, RefMut},
  5. fmt::{Debug, Display},
  6. ops::{Add, Div, Mul, Not, Sub},
  7. rc::Rc,
  8. sync::Arc,
  9. };
  10. /// Store state between component renders.
  11. ///
  12. /// ## Dioxus equivalent of useState, designed for Rust
  13. ///
  14. /// The Dioxus version of `useState` for state management inside components. It allows you to ergonomically store and
  15. /// modify state between component renders. When the state is updated, the component will re-render.
  16. ///
  17. ///
  18. /// ```ignore
  19. /// const Example: Component = |cx| {
  20. /// let count = use_state(&cx, || 0);
  21. ///
  22. /// cx.render(rsx! {
  23. /// div {
  24. /// h1 { "Count: {count}" }
  25. /// button { onclick: move |_| *count.modify() += 1, "Increment" }
  26. /// button { onclick: move |_| *count.modify() -= 1, "Decrement" }
  27. /// }
  28. /// ))
  29. /// }
  30. /// ```
  31. pub fn use_state<'a, T: 'static>(
  32. cx: &'a ScopeState,
  33. initial_state_fn: impl FnOnce() -> T,
  34. ) -> &'a UseState<T> {
  35. let hook = cx.use_hook(move |_| {
  36. let current_val = Rc::new(initial_state_fn());
  37. let update_callback = cx.schedule_update();
  38. let slot = Rc::new(RefCell::new(current_val.clone()));
  39. let setter = Rc::new({
  40. dioxus_core::to_owned![update_callback, slot];
  41. move |new| {
  42. {
  43. let mut slot = slot.borrow_mut();
  44. // if there's only one reference (weak or otherwise), we can just swap the values
  45. // Typically happens when the state is set multiple times - we don't want to create a new Rc for each new value
  46. if let Some(val) = Rc::get_mut(&mut slot) {
  47. *val = new;
  48. } else {
  49. *slot = Rc::new(new);
  50. }
  51. }
  52. update_callback();
  53. }
  54. });
  55. UseState {
  56. current_val,
  57. update_callback,
  58. setter,
  59. slot,
  60. }
  61. });
  62. hook.current_val = hook.slot.borrow().clone();
  63. hook
  64. }
  65. pub struct UseState<T: 'static> {
  66. pub(crate) current_val: Rc<T>,
  67. pub(crate) update_callback: Arc<dyn Fn()>,
  68. pub(crate) setter: Rc<dyn Fn(T)>,
  69. pub(crate) slot: Rc<RefCell<Rc<T>>>,
  70. }
  71. impl<T: 'static> UseState<T> {
  72. /// Set the state to a new value.
  73. pub fn set(&self, new: T) {
  74. (self.setter)(new);
  75. }
  76. /// Get the current value of the state by cloning its container Rc.
  77. ///
  78. /// This is useful when you are dealing with state in async contexts but need
  79. /// to know the current value. You are not given a reference to the state.
  80. ///
  81. /// # Examples
  82. /// An async context might need to know the current value:
  83. ///
  84. /// ```rust, ignore
  85. /// fn component(cx: Scope) -> Element {
  86. /// let (count, set_count) = use_state(&cx, || 0);
  87. /// cx.spawn({
  88. /// let set_count = set_count.to_owned();
  89. /// async move {
  90. /// let current = set_count.current();
  91. /// }
  92. /// })
  93. /// }
  94. /// ```
  95. #[must_use]
  96. pub fn current(&self) -> Rc<T> {
  97. self.slot.borrow().clone()
  98. }
  99. /// Get the `setter` function directly without the `UseState` wrapper.
  100. ///
  101. /// This is useful for passing the setter function to other components.
  102. ///
  103. /// However, for most cases, calling `to_owned` o`UseState`te is the
  104. /// preferred way to get "anoth`set_state`tate handle.
  105. ///
  106. ///
  107. /// # Examples
  108. /// A component might require an `Rc<dyn Fn(T)>` as an input to set a value.
  109. ///
  110. /// ```rust, ignore
  111. /// fn component(cx: Scope) -> Element {
  112. /// let (value, set_value) = use_state(&cx, || 0);
  113. ///
  114. /// rsx!{
  115. /// Component {
  116. /// handler: set_val.setter()
  117. /// }
  118. /// }
  119. /// }
  120. /// ```
  121. #[must_use]
  122. pub fn setter(&self) -> Rc<dyn Fn(T)> {
  123. self.setter.clone()
  124. }
  125. /// Set the state to a new value, using the current state value as a reference.
  126. ///
  127. /// This is similar to passing a closure to React's `set_value` function.
  128. ///
  129. /// # Examples
  130. ///
  131. /// Basic usage:
  132. /// ```rust
  133. /// # use dioxus_core::prelude::*;
  134. /// # use dioxus_hooks::*;
  135. /// fn component(cx: Scope) -> Element {
  136. /// let (value, set_value) = use_state(&cx, || 0);
  137. ///
  138. /// // to increment the value
  139. /// set_value.modify(|v| v + 1);
  140. ///
  141. /// // usage in async
  142. /// cx.spawn({
  143. /// let set_value = set_value.to_owned();
  144. /// async move {
  145. /// set_value.modify(|v| v + 1);
  146. /// }
  147. /// });
  148. ///
  149. /// # todo!()
  150. /// }
  151. /// ```
  152. pub fn modify(&self, f: impl FnOnce(&T) -> T) {
  153. let new_val = {
  154. let current = self.slot.borrow();
  155. f(current.as_ref())
  156. };
  157. (self.setter)(new_val);
  158. }
  159. /// Get the value of the state when this handle was created.
  160. ///
  161. /// This method is useful when you want an `Rc` around the data to cheaply
  162. /// pass it around your app.
  163. ///
  164. /// ## Warning
  165. ///
  166. /// This will return a stale value if used within async contexts.
  167. ///
  168. /// Try `current` to get the real current value of the state.
  169. ///
  170. /// ## Example
  171. ///
  172. /// ```rust, ignore
  173. /// # use dioxus_core::prelude::*;
  174. /// # use dioxus_hooks::*;
  175. /// fn component(cx: Scope) -> Element {
  176. /// let (value, set_value) = use_state(&cx, || 0);
  177. ///
  178. /// let as_rc = set_value.get();
  179. /// assert_eq!(as_rc.as_ref(), &0);
  180. ///
  181. /// # todo!()
  182. /// }
  183. /// ```
  184. #[must_use]
  185. pub fn get(&self) -> &T {
  186. &self.current_val
  187. }
  188. #[must_use]
  189. pub fn get_rc(&self) -> &Rc<T> {
  190. &self.current_val
  191. }
  192. /// Mark the component that create this [`UseState`] as dirty, forcing it to re-render.
  193. ///
  194. /// ```rust, ignore
  195. /// fn component(cx: Scope) -> Element {
  196. /// let (count, set_count) = use_state(&cx, || 0);
  197. /// cx.spawn({
  198. /// let set_count = set_count.to_owned();
  199. /// async move {
  200. /// // for the component to re-render
  201. /// set_count.needs_update();
  202. /// }
  203. /// })
  204. /// }
  205. /// ```
  206. pub fn needs_update(&self) {
  207. (self.update_callback)();
  208. }
  209. }
  210. impl<T: Clone> UseState<T> {
  211. /// Get a mutable handle to the value by calling `ToOwned::to_owned` on the
  212. /// current value.
  213. ///
  214. /// This is essentially cloning the underlying value and then setting it,
  215. /// giving you a mutable handle in the process. This method is intended for
  216. /// types that are cheaply cloneable.
  217. ///
  218. /// If you are comfortable dealing with `RefMut`, then you can use `make_mut` to get
  219. /// the underlying slot. However, be careful with `RefMut` since you might panic
  220. /// if the `RefCell` is left open.
  221. ///
  222. /// # Examples
  223. ///
  224. /// ```
  225. /// let (val, set_val) = use_state(&cx, || 0);
  226. ///
  227. /// set_val.with_mut(|v| *v = 1);
  228. /// ```
  229. pub fn with_mut(&self, apply: impl FnOnce(&mut T)) {
  230. let mut slot = self.slot.borrow_mut();
  231. let mut inner = slot.as_ref().to_owned();
  232. apply(&mut inner);
  233. if let Some(new) = Rc::get_mut(&mut slot) {
  234. *new = inner;
  235. } else {
  236. *slot = Rc::new(inner);
  237. }
  238. self.needs_update();
  239. }
  240. /// Get a mutable handle to the value by calling `ToOwned::to_owned` on the
  241. /// current value.
  242. ///
  243. /// This is essentially cloning the underlying value and then setting it,
  244. /// giving you a mutable handle in the process. This method is intended for
  245. /// types that are cheaply cloneable.
  246. ///
  247. /// # Warning
  248. /// Be careful with `RefMut` since you might panic if the `RefCell` is left open!
  249. ///
  250. /// # Examples
  251. ///
  252. /// ```
  253. /// let (val, set_val) = use_state(&cx, || 0);
  254. ///
  255. /// *set_val.make_mut() += 1;
  256. /// ```
  257. #[must_use]
  258. pub fn make_mut(&self) -> RefMut<T> {
  259. let mut slot = self.slot.borrow_mut();
  260. self.needs_update();
  261. if Rc::strong_count(&*slot) > 0 {
  262. *slot = Rc::new(slot.as_ref().to_owned());
  263. }
  264. RefMut::map(slot, |rc| Rc::get_mut(rc).expect("the hard count to be 0"))
  265. }
  266. /// Convert this handle to a tuple of the value and the handle itself.
  267. #[must_use]
  268. pub fn split(&self) -> (&T, &Self) {
  269. (&self.current_val, self)
  270. }
  271. }
  272. impl<T: 'static> Clone for UseState<T> {
  273. fn clone(&self) -> Self {
  274. UseState {
  275. current_val: self.current_val.clone(),
  276. update_callback: self.update_callback.clone(),
  277. setter: self.setter.clone(),
  278. slot: self.slot.clone(),
  279. }
  280. }
  281. }
  282. impl<'a, T: 'static + Display> std::fmt::Display for UseState<T> {
  283. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  284. write!(f, "{}", self.current_val)
  285. }
  286. }
  287. impl<'a, T: std::fmt::Binary> std::fmt::Binary for UseState<T> {
  288. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  289. write!(f, "{:b}", self.current_val.as_ref())
  290. }
  291. }
  292. impl<T: PartialEq> PartialEq<T> for UseState<T> {
  293. fn eq(&self, other: &T) -> bool {
  294. self.current_val.as_ref() == other
  295. }
  296. }
  297. // todo: this but for more interesting conrete types
  298. impl PartialEq<bool> for &UseState<bool> {
  299. fn eq(&self, other: &bool) -> bool {
  300. self.current_val.as_ref() == other
  301. }
  302. }
  303. impl<T: PartialEq> PartialEq<UseState<T>> for UseState<T> {
  304. fn eq(&self, other: &UseState<T>) -> bool {
  305. Rc::ptr_eq(&self.current_val, &other.current_val)
  306. }
  307. }
  308. impl<T: Debug> Debug for UseState<T> {
  309. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  310. write!(f, "{:?}", self.current_val)
  311. }
  312. }
  313. impl<'a, T> std::ops::Deref for UseState<T> {
  314. type Target = T;
  315. fn deref(&self) -> &Self::Target {
  316. self.current_val.as_ref()
  317. }
  318. }
  319. impl<T: Not + Copy> std::ops::Not for &UseState<T> {
  320. type Output = <T as std::ops::Not>::Output;
  321. fn not(self) -> Self::Output {
  322. self.current_val.not()
  323. }
  324. }
  325. impl<T: Not + Copy> std::ops::Not for UseState<T> {
  326. type Output = <T as std::ops::Not>::Output;
  327. fn not(self) -> Self::Output {
  328. self.current_val.not()
  329. }
  330. }
  331. impl<T: std::ops::Add + Copy> std::ops::Add<T> for &UseState<T> {
  332. type Output = <T as std::ops::Add>::Output;
  333. fn add(self, other: T) -> Self::Output {
  334. *self.current_val.as_ref() + other
  335. }
  336. }
  337. impl<T: std::ops::Sub + Copy> std::ops::Sub<T> for &UseState<T> {
  338. type Output = <T as std::ops::Sub>::Output;
  339. fn sub(self, other: T) -> Self::Output {
  340. *self.current_val.as_ref() - other
  341. }
  342. }
  343. impl<T: std::ops::Div + Copy> std::ops::Div<T> for &UseState<T> {
  344. type Output = <T as std::ops::Div>::Output;
  345. fn div(self, other: T) -> Self::Output {
  346. *self.current_val.as_ref() / other
  347. }
  348. }
  349. impl<T: std::ops::Mul + Copy> std::ops::Mul<T> for &UseState<T> {
  350. type Output = <T as std::ops::Mul>::Output;
  351. fn mul(self, other: T) -> Self::Output {
  352. *self.current_val.as_ref() * other
  353. }
  354. }
  355. impl<T: Add<Output = T> + Copy> std::ops::AddAssign<T> for &UseState<T> {
  356. fn add_assign(&mut self, rhs: T) {
  357. self.set((*self.current()) + rhs);
  358. }
  359. }
  360. impl<T: Sub<Output = T> + Copy> std::ops::SubAssign<T> for &UseState<T> {
  361. fn sub_assign(&mut self, rhs: T) {
  362. self.set((*self.current()) - rhs);
  363. }
  364. }
  365. impl<T: Mul<Output = T> + Copy> std::ops::MulAssign<T> for &UseState<T> {
  366. fn mul_assign(&mut self, rhs: T) {
  367. self.set((*self.current()) * rhs);
  368. }
  369. }
  370. impl<T: Div<Output = T> + Copy> std::ops::DivAssign<T> for &UseState<T> {
  371. fn div_assign(&mut self, rhs: T) {
  372. self.set((*self.current()) / rhs);
  373. }
  374. }
  375. impl<T: Add<Output = T> + Copy> std::ops::AddAssign<T> for UseState<T> {
  376. fn add_assign(&mut self, rhs: T) {
  377. self.set((*self.current()) + rhs);
  378. }
  379. }
  380. impl<T: Sub<Output = T> + Copy> std::ops::SubAssign<T> for UseState<T> {
  381. fn sub_assign(&mut self, rhs: T) {
  382. self.set((*self.current()) - rhs);
  383. }
  384. }
  385. impl<T: Mul<Output = T> + Copy> std::ops::MulAssign<T> for UseState<T> {
  386. fn mul_assign(&mut self, rhs: T) {
  387. self.set((*self.current()) * rhs);
  388. }
  389. }
  390. impl<T: Div<Output = T> + Copy> std::ops::DivAssign<T> for UseState<T> {
  391. fn div_assign(&mut self, rhs: T) {
  392. self.set((*self.current()) / rhs);
  393. }
  394. }
  395. #[test]
  396. fn api_makes_sense() {
  397. #[allow(unused)]
  398. fn app(cx: Scope) -> Element {
  399. let val = use_state(&cx, || 0);
  400. val.set(0);
  401. val.modify(|v| v + 1);
  402. let real_current = val.current();
  403. match val.get() {
  404. 10 => {
  405. val.set(20);
  406. val.modify(|v| v + 1);
  407. }
  408. 20 => {}
  409. _ => {
  410. println!("{real_current}");
  411. }
  412. }
  413. cx.spawn({
  414. dioxus_core::to_owned![val];
  415. async move {
  416. val.modify(|f| f + 1);
  417. }
  418. });
  419. cx.render(LazyNodes::new(|f| f.static_text("asd")))
  420. }
  421. }