lib.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. use std::collections::HashMap;
  2. use dioxus_core::prelude::*;
  3. /*
  4. a form of use_state explicitly for map-style collections (BTreeMap, HashMap, etc).
  5. Why?
  6. ---
  7. Traditionally, it's possible to use the "use_state" hook for collections in the React world.
  8. Adding a new entry would look something similar to:
  9. ```js
  10. let (map, set_map) = useState({});
  11. set_map({ ...map, [key]: value });
  12. ```
  13. The new value then causes the appropriate update when passed into children.
  14. This is moderately efficient because the fields of the map are moved, but the data itself is not cloned.
  15. However, if you used similar approach with Dioxus:
  16. ```rust
  17. let (map, set_map) = use_state(cx, || HashMap::new());
  18. set_map({
  19. let mut newmap = map.clone();
  20. newmap.set(key, value);
  21. newmap
  22. })
  23. ```
  24. Unfortunately, you'd be cloning the entire state every time a value is changed. The obvious solution is to
  25. wrap every element in the HashMap with an Rc. That way, cloning the HashMap is on par with its JS equivalent.
  26. Fortunately, we can make this operation even more efficient in Dioxus, leveraging the borrow rules of Rust.
  27. This hook provides a memoized collection, memoized setters, and memoized getters. This particular hook is
  28. extremely powerful for implementing lists and supporting core state management needs for small apps.
  29. If you need something even more powerful, check out the dedicated atomic state management Dioxus Dataflow, which
  30. uses the same memoization on top of the use_context API.
  31. Here's a fully-functional todo app using the use_map API:
  32. ```rust
  33. static TodoList: FC<()> = |cx| {
  34. let todos = use_map(cx, || HashMap::new());
  35. let input = use_ref(|| None);
  36. cx.render(rsx!{
  37. div {
  38. button {
  39. "Add todo"
  40. onclick: move |_| {
  41. let new_todo = TodoItem::new(input.contents());
  42. todos.insert(new_todo.id.clone(), new_todo);
  43. input.clear();
  44. }
  45. }
  46. button {
  47. "Clear todos"
  48. onclick: move |_| todos.clear()
  49. }
  50. input {
  51. placeholder: "What needs to be done?"
  52. ref: input
  53. }
  54. ul {
  55. {todos.iter().map(|todo| rsx!(
  56. li {
  57. key: todo.id
  58. span { "{todo.content}" }
  59. button {"x", onclick: move |_| todos.remove(todo.key.clone())}
  60. }
  61. ))}
  62. }
  63. }
  64. })
  65. }
  66. ```
  67. */
  68. fn use_map() {}
  69. // a form of "use_state" that allows collection memoization
  70. // Elements are received as Rc<T> in case the underlying collection is shuffled around
  71. // Setters/getters can be generated
  72. fn use_collection<'a, T: Collection>(
  73. cx: &impl Scoped<'a>,
  74. f: impl Fn() -> T,
  75. ) -> CollectionHandle<'a, T> {
  76. cx.use_hook(
  77. || {},
  78. |h| {
  79. //
  80. CollectionHandle {
  81. _p: Default::default(),
  82. }
  83. },
  84. |h| {},
  85. )
  86. }
  87. struct CollectionMemo {}
  88. struct CollectionHandle<'a, T: Collection> {
  89. _p: std::marker::PhantomData<&'a T>,
  90. }
  91. trait Collection {}
  92. impl<K, V> Collection for std::collections::HashMap<K, V> {}
  93. struct MapCollection<K, V> {
  94. inner: HashMap<K, V>,
  95. }
  96. impl<K, V> MapCollection<K, V> {
  97. fn set(&self, key: K, val: V) {
  98. //
  99. }
  100. }