1
0

memo.rs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #[tokio::test]
  2. async fn memo_updates() {
  3. use std::cell::RefCell;
  4. use dioxus::prelude::*;
  5. thread_local! {
  6. static VEC_SIGNAL: RefCell<Option<Signal<Vec<usize>, SyncStorage>>> = const { RefCell::new(None) };
  7. }
  8. fn app() -> Element {
  9. let mut vec = use_signal_sync(|| vec![0, 1, 2]);
  10. // Signals should update if they are changed from another thread
  11. use_hook(|| {
  12. VEC_SIGNAL.with(|cell| {
  13. *cell.borrow_mut() = Some(vec);
  14. });
  15. std::thread::spawn(move || {
  16. std::thread::sleep(std::time::Duration::from_millis(100));
  17. vec.push(5);
  18. });
  19. });
  20. let len = vec.len();
  21. let len_memo = use_memo(move || vec.len());
  22. // Make sure memos that update in the middle of a component work
  23. if generation() < 2 {
  24. vec.push(len);
  25. }
  26. // The memo should always be up to date
  27. assert_eq!(vec.len(), len_memo());
  28. rsx! {
  29. for i in 0..len {
  30. Child { index: i, vec }
  31. }
  32. }
  33. }
  34. #[component]
  35. fn Child(index: usize, vec: Signal<Vec<usize>, SyncStorage>) -> Element {
  36. // This memo should not rerun after the element is removed
  37. let item = use_memo(move || vec.read()[index]);
  38. rsx! {
  39. div { "Item: {item}" }
  40. }
  41. }
  42. let race = async move {
  43. let mut dom = VirtualDom::new(app);
  44. dom.rebuild_in_place();
  45. let mut signal = VEC_SIGNAL.with(|cell| (*cell.borrow()).unwrap());
  46. // Wait for the signal to update
  47. for _ in 0..2 {
  48. dom.wait_for_work().await;
  49. dom.render_immediate(&mut dioxus::dioxus_core::NoOpMutations);
  50. }
  51. assert_eq!(signal(), vec![0, 1, 2, 3, 4, 5]);
  52. // Remove each element from the vec
  53. for _ in 0..6 {
  54. signal.pop();
  55. dom.wait_for_work().await;
  56. dom.render_immediate(&mut dioxus::dioxus_core::NoOpMutations);
  57. println!("Signal: {signal:?}");
  58. }
  59. };
  60. tokio::select! {
  61. _ = race => {},
  62. _ = tokio::time::sleep(std::time::Duration::from_millis(1000)) => panic!("timed out")
  63. };
  64. }
  65. #[tokio::test]
  66. async fn use_memo_only_triggers_one_update() {
  67. use dioxus::prelude::*;
  68. use std::cell::RefCell;
  69. thread_local! {
  70. static VEC_SIGNAL: RefCell<Vec<usize>> = const { RefCell::new(Vec::new()) };
  71. }
  72. fn app() -> Element {
  73. let mut count = use_signal(|| 0);
  74. let memorized = use_memo(move || dbg!(count() * 2));
  75. use_memo(move || {
  76. println!("reading doubled");
  77. let doubled = memorized();
  78. VEC_SIGNAL.with_borrow_mut(|v| v.push(doubled))
  79. });
  80. // Writing to count many times in a row should not cause the memo to update other subscribers multiple times
  81. use_hook(move || {
  82. for _ in 0..10 {
  83. count += 1;
  84. // Reading the memo each time will trigger the memo to rerun immediately, but the VEC_SIGNAL should still only rerun once
  85. println!("doubled {memorized}");
  86. }
  87. });
  88. rsx! {}
  89. }
  90. let mut dom = VirtualDom::new(app);
  91. dom.rebuild_in_place();
  92. tokio::select! {
  93. _ = dom.wait_for_work() => {},
  94. _ = tokio::time::sleep(std::time::Duration::from_millis(100)) => {}
  95. };
  96. dom.render_immediate(&mut dioxus::dioxus_core::NoOpMutations);
  97. assert_eq!(VEC_SIGNAL.with(|v| v.borrow().clone()), vec![0, 20]);
  98. }