use_collection.rs 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. /*
  2. a form of use_state explicitly for map-style collections (BTreeMap, HashMap, etc).
  3. Why?
  4. ---
  5. Traditionally, it's possible to use the "use_state" hook for collections in the React world.
  6. Adding a new entry would look something similar to:
  7. ```js
  8. let (map, set_map) = useState({});
  9. set_map({ ...map, [key]: value });
  10. ```
  11. The new value then causes the appropriate update when passed into children.
  12. This is moderately efficient because the fields of the map are moved, but the data itself is not cloned.
  13. However, if you used similar approach with Dioxus:
  14. ```rust
  15. let (map, set_map) = use_state(cx, || HashMap::new());
  16. set_map({
  17. let mut newmap = map.clone();
  18. newmap.set(key, value);
  19. newmap
  20. })
  21. ```
  22. Unfortunately, you'd be cloning the entire state every time a value is changed. The obvious solution is to
  23. wrap every element in the HashMap with an Rc. That way, cloning the HashMap is on par with its JS equivalent.
  24. Fortunately, we can make this operation even more efficient in Dioxus, leveraging the borrow rules of Rust.
  25. This hook provides a memoized collection, memoized setters, and memoized getters. This particular hook is
  26. extremely powerful for implementing lists and supporting core state management needs for small apps.
  27. If you need something even more powerful, check out the dedicated atomic state management Dioxus Dataflow, which
  28. uses the same memoization on top of the use_context API.
  29. Here's a fully-functional todo app using the use_map API:
  30. ```rust
  31. static TodoList: Component = |cx| {
  32. let todos = use_map(cx, || HashMap::new());
  33. let input = use_ref(|| None);
  34. cx.render(rsx!{
  35. div {
  36. button {
  37. "Add todo"
  38. onclick: move |_| {
  39. let new_todo = TodoItem::new(input.contents());
  40. todos.insert(new_todo.id.clone(), new_todo);
  41. input.clear();
  42. }
  43. }
  44. button {
  45. "Clear todos"
  46. onclick: move |_| todos.clear()
  47. }
  48. input {
  49. placeholder: "What needs to be done?"
  50. ref: input
  51. }
  52. ul {
  53. {todos.iter().map(|todo| rsx!(
  54. li {
  55. key: todo.id
  56. span { "{todo.content}" }
  57. button {"x", onclick: move |_| todos.remove(todo.key.clone())}
  58. }
  59. ))}
  60. }
  61. }
  62. })
  63. }
  64. ```
  65. */