mod.rs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. mod handle;
  2. mod owned;
  3. pub use handle::*;
  4. pub use owned::*;
  5. use dioxus_core::prelude::*;
  6. use std::{
  7. cell::{Cell, RefCell},
  8. rc::Rc,
  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. /// Dioxus' use_state basically wraps a RefCell with helper methods and integrates it with the VirtualDOM update system.
  18. ///
  19. /// [`use_state`] exposes a few helper methods to modify the underlying state:
  20. /// - `.set(new)` allows you to override the "work in progress" value with a new value
  21. /// - `.get_mut()` allows you to modify the WIP value
  22. /// - `.get_wip()` allows you to access the WIP value
  23. /// - `.deref()` provides the previous value (often done implicitly, though a manual dereference with `*` might be required)
  24. ///
  25. /// Additionally, a ton of std::ops traits are implemented for the `UseState` wrapper, meaning any mutative type operations
  26. /// will automatically be called on the WIP value.
  27. ///
  28. /// ## Combinators
  29. ///
  30. /// On top of the methods to set/get state, `use_state` also supports fancy combinators to extend its functionality:
  31. /// - `.classic()` and `.split()` convert the hook into the classic React-style hook
  32. /// ```rust
  33. /// let (state, set_state) = use_state(&cx, || 10).split()
  34. /// ```
  35. ///
  36. ///
  37. /// Usage:
  38. ///
  39. /// ```ignore
  40. /// const Example: Component = |cx| {
  41. /// let counter = use_state(&cx, || 0);
  42. ///
  43. /// cx.render(rsx! {
  44. /// div {
  45. /// h1 { "Counter: {counter}" }
  46. /// button { onclick: move |_| counter += 1, "Increment" }
  47. /// button { onclick: move |_| counter -= 1, "Decrement" }
  48. /// }
  49. /// ))
  50. /// }
  51. /// ```
  52. pub fn use_state<'a, T: 'static>(
  53. cx: &'a ScopeState,
  54. initial_state_fn: impl FnOnce() -> T,
  55. ) -> UseState<'a, T> {
  56. let hook = cx.use_hook(move |_| UseStateOwned {
  57. current_val: Rc::new(initial_state_fn()),
  58. update_callback: cx.schedule_update(),
  59. wip: Rc::new(RefCell::new(None)),
  60. update_scheuled: Cell::new(false),
  61. });
  62. hook.update_scheuled.set(false);
  63. let mut new_val = hook.wip.borrow_mut();
  64. if new_val.is_some() {
  65. // if there's only one reference (weak or otherwise), we can just swap the values
  66. if let Some(val) = Rc::get_mut(&mut hook.current_val) {
  67. *val = new_val.take().unwrap();
  68. } else {
  69. hook.current_val = Rc::new(new_val.take().unwrap());
  70. }
  71. }
  72. UseState(hook)
  73. }