use_state.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  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<T: 'static>(
  32. cx: &ScopeState,
  33. initial_state_fn: impl FnOnce() -> T,
  34. ) -> &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. 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 = use_state(cx, || 0);
  87. /// cx.spawn({
  88. /// let set_count = 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` on the state is the
  104. /// preferred way to get "another" state 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 = use_state(cx, || 0);
  113. ///
  114. /// rsx!{
  115. /// Component {
  116. /// handler: value.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, ignore
  133. /// # use dioxus_core::prelude::*;
  134. /// # use dioxus_hooks::*;
  135. /// fn component(cx: Scope) -> Element {
  136. /// let value = use_state(cx, || 0);
  137. ///
  138. /// // to increment the value
  139. /// value.modify(|v| v + 1);
  140. ///
  141. /// // usage in async
  142. /// cx.spawn({
  143. /// let value = value.to_owned();
  144. /// async move {
  145. /// 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 = use_state(cx, || 0);
  177. ///
  178. /// let as_rc = 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 = use_state(cx, || 0);
  197. /// cx.spawn({
  198. /// let count = count.to_owned();
  199. /// async move {
  200. /// // for the component to re-render
  201. /// 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. /// ```rust, ignore
  225. /// let val = use_state(cx, || 0);
  226. ///
  227. /// 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. /// ```rust, ignore
  253. /// let val = use_state(cx, || 0);
  254. ///
  255. /// *val.make_mut() += 1;
  256. /// ```
  257. #[must_use]
  258. #[allow(clippy::missing_panics_doc)]
  259. pub fn make_mut(&self) -> RefMut<T> {
  260. let mut slot = self.slot.borrow_mut();
  261. self.needs_update();
  262. if Rc::strong_count(&*slot) > 0 {
  263. *slot = Rc::new(slot.as_ref().to_owned());
  264. }
  265. RefMut::map(slot, |rc| Rc::get_mut(rc).expect("the hard count to be 0"))
  266. }
  267. /// Convert this handle to a tuple of the value and the handle itself.
  268. #[must_use]
  269. pub fn split(&self) -> (&T, &Self) {
  270. (&self.current_val, self)
  271. }
  272. }
  273. impl<T: 'static> Clone for UseState<T> {
  274. fn clone(&self) -> Self {
  275. UseState {
  276. current_val: self.current_val.clone(),
  277. update_callback: self.update_callback.clone(),
  278. setter: self.setter.clone(),
  279. slot: self.slot.clone(),
  280. }
  281. }
  282. }
  283. impl<T: 'static + Display> std::fmt::Display for UseState<T> {
  284. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  285. write!(f, "{}", self.current_val)
  286. }
  287. }
  288. impl<T: std::fmt::Binary> std::fmt::Binary for UseState<T> {
  289. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  290. write!(f, "{:b}", self.current_val.as_ref())
  291. }
  292. }
  293. impl<T: PartialEq> PartialEq<T> for UseState<T> {
  294. fn eq(&self, other: &T) -> bool {
  295. self.current_val.as_ref() == other
  296. }
  297. }
  298. // todo: this but for more interesting conrete types
  299. impl PartialEq<bool> for &UseState<bool> {
  300. fn eq(&self, other: &bool) -> bool {
  301. self.current_val.as_ref() == other
  302. }
  303. }
  304. impl<T> PartialEq<UseState<T>> for UseState<T> {
  305. fn eq(&self, other: &UseState<T>) -> bool {
  306. Rc::ptr_eq(&self.current_val, &other.current_val)
  307. }
  308. }
  309. impl<T: std::cmp::PartialOrd> PartialOrd<T> for UseState<T> {
  310. fn ge(&self, other: &T) -> bool {
  311. *self.current_val >= *other
  312. }
  313. fn gt(&self, other: &T) -> bool {
  314. *self.current_val > *other
  315. }
  316. fn le(&self, other: &T) -> bool {
  317. *self.current_val <= *other
  318. }
  319. fn lt(&self, other: &T) -> bool {
  320. *self.current_val < *other
  321. }
  322. fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
  323. (*self.current_val).partial_cmp(other)
  324. }
  325. }
  326. impl<T: std::cmp::PartialOrd> PartialOrd<UseState<T>> for UseState<T> {
  327. fn ge(&self, other: &UseState<T>) -> bool {
  328. self.current_val >= other.current_val
  329. }
  330. fn gt(&self, other: &UseState<T>) -> bool {
  331. self.current_val > other.current_val
  332. }
  333. fn le(&self, other: &UseState<T>) -> bool {
  334. self.current_val <= other.current_val
  335. }
  336. fn lt(&self, other: &UseState<T>) -> bool {
  337. self.current_val < other.current_val
  338. }
  339. fn partial_cmp(&self, other: &UseState<T>) -> Option<std::cmp::Ordering> {
  340. self.current_val.partial_cmp(&other.current_val)
  341. }
  342. }
  343. impl<T: Debug> Debug for UseState<T> {
  344. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  345. write!(f, "{:?}", self.current_val)
  346. }
  347. }
  348. impl<T> std::ops::Deref for UseState<T> {
  349. type Target = T;
  350. fn deref(&self) -> &Self::Target {
  351. self.current_val.as_ref()
  352. }
  353. }
  354. impl<T: Not + Copy> std::ops::Not for &UseState<T> {
  355. type Output = <T as std::ops::Not>::Output;
  356. fn not(self) -> Self::Output {
  357. self.current_val.not()
  358. }
  359. }
  360. impl<T: Not + Copy> std::ops::Not for UseState<T> {
  361. type Output = <T as std::ops::Not>::Output;
  362. fn not(self) -> Self::Output {
  363. self.current_val.not()
  364. }
  365. }
  366. impl<T: std::ops::Add + Copy> std::ops::Add<T> for &UseState<T> {
  367. type Output = <T as std::ops::Add>::Output;
  368. fn add(self, other: T) -> Self::Output {
  369. *self.current_val.as_ref() + other
  370. }
  371. }
  372. impl<T: std::ops::Sub + Copy> std::ops::Sub<T> for &UseState<T> {
  373. type Output = <T as std::ops::Sub>::Output;
  374. fn sub(self, other: T) -> Self::Output {
  375. *self.current_val.as_ref() - other
  376. }
  377. }
  378. impl<T: std::ops::Div + Copy> std::ops::Div<T> for &UseState<T> {
  379. type Output = <T as std::ops::Div>::Output;
  380. fn div(self, other: T) -> Self::Output {
  381. *self.current_val.as_ref() / other
  382. }
  383. }
  384. impl<T: std::ops::Mul + Copy> std::ops::Mul<T> for &UseState<T> {
  385. type Output = <T as std::ops::Mul>::Output;
  386. fn mul(self, other: T) -> Self::Output {
  387. *self.current_val.as_ref() * other
  388. }
  389. }
  390. impl<T: Add<Output = T> + Copy> std::ops::AddAssign<T> for &UseState<T> {
  391. fn add_assign(&mut self, rhs: T) {
  392. self.set((*self.current()) + rhs);
  393. }
  394. }
  395. impl<T: Sub<Output = T> + Copy> std::ops::SubAssign<T> for &UseState<T> {
  396. fn sub_assign(&mut self, rhs: T) {
  397. self.set((*self.current()) - rhs);
  398. }
  399. }
  400. impl<T: Mul<Output = T> + Copy> std::ops::MulAssign<T> for &UseState<T> {
  401. fn mul_assign(&mut self, rhs: T) {
  402. self.set((*self.current()) * rhs);
  403. }
  404. }
  405. impl<T: Div<Output = T> + Copy> std::ops::DivAssign<T> for &UseState<T> {
  406. fn div_assign(&mut self, rhs: T) {
  407. self.set((*self.current()) / rhs);
  408. }
  409. }
  410. impl<T: Add<Output = T> + Copy> std::ops::AddAssign<T> for UseState<T> {
  411. fn add_assign(&mut self, rhs: T) {
  412. self.set((*self.current()) + rhs);
  413. }
  414. }
  415. impl<T: Sub<Output = T> + Copy> std::ops::SubAssign<T> for UseState<T> {
  416. fn sub_assign(&mut self, rhs: T) {
  417. self.set((*self.current()) - rhs);
  418. }
  419. }
  420. impl<T: Mul<Output = T> + Copy> std::ops::MulAssign<T> for UseState<T> {
  421. fn mul_assign(&mut self, rhs: T) {
  422. self.set((*self.current()) * rhs);
  423. }
  424. }
  425. impl<T: Div<Output = T> + Copy> std::ops::DivAssign<T> for UseState<T> {
  426. fn div_assign(&mut self, rhs: T) {
  427. self.set((*self.current()) / rhs);
  428. }
  429. }
  430. #[test]
  431. fn api_makes_sense() {
  432. #[allow(unused)]
  433. fn app(cx: Scope) -> Element {
  434. let val = use_state(cx, || 0);
  435. val.set(0);
  436. val.modify(|v| v + 1);
  437. let real_current = val.current();
  438. match val.get() {
  439. 10 => {
  440. val.set(20);
  441. val.modify(|v| v + 1);
  442. }
  443. 20 => {}
  444. _ => {
  445. println!("{real_current}");
  446. }
  447. }
  448. cx.spawn({
  449. to_owned![val];
  450. async move {
  451. val.modify(|f| f + 1);
  452. }
  453. });
  454. // cx.render(LazyNodes::new(|f| f.static_text("asd")))
  455. todo!()
  456. }
  457. }