123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- #[tokio::test]
- async fn memo_updates() {
- use std::cell::RefCell;
- use dioxus::prelude::*;
- thread_local! {
- static VEC_SIGNAL: RefCell<Option<Signal<Vec<usize>, SyncStorage>>> = const { RefCell::new(None) };
- }
- fn app() -> Element {
- let mut vec = use_signal_sync(|| vec![0, 1, 2]);
- // Signals should update if they are changed from another thread
- use_hook(|| {
- VEC_SIGNAL.with(|cell| {
- *cell.borrow_mut() = Some(vec);
- });
- std::thread::spawn(move || {
- std::thread::sleep(std::time::Duration::from_millis(100));
- vec.push(5);
- });
- });
- let len = vec.len();
- let len_memo = use_memo(move || vec.len());
- // Make sure memos that update in the middle of a component work
- if generation() < 2 {
- vec.push(len);
- }
- // The memo should always be up to date
- assert_eq!(vec.len(), len_memo());
- rsx! {
- for i in 0..len {
- Child { index: i, vec }
- }
- }
- }
- #[component]
- fn Child(index: usize, vec: Signal<Vec<usize>, SyncStorage>) -> Element {
- // This memo should not rerun after the element is removed
- let item = use_memo(move || vec.read()[index]);
- rsx! {
- div { "Item: {item}" }
- }
- }
- let race = async move {
- let mut dom = VirtualDom::new(app);
- dom.rebuild_in_place();
- let mut signal = VEC_SIGNAL.with(|cell| (*cell.borrow()).unwrap());
- // Wait for the signal to update
- for _ in 0..2 {
- dom.wait_for_work().await;
- dom.render_immediate(&mut dioxus::dioxus_core::NoOpMutations);
- }
- assert_eq!(signal(), vec![0, 1, 2, 3, 4, 5]);
- // Remove each element from the vec
- for _ in 0..6 {
- signal.pop();
- dom.wait_for_work().await;
- dom.render_immediate(&mut dioxus::dioxus_core::NoOpMutations);
- println!("Signal: {signal:?}");
- }
- };
- tokio::select! {
- _ = race => {},
- _ = tokio::time::sleep(std::time::Duration::from_millis(1000)) => panic!("timed out")
- };
- }
- #[tokio::test]
- async fn use_memo_only_triggers_one_update() {
- use dioxus::prelude::*;
- use std::cell::RefCell;
- thread_local! {
- static VEC_SIGNAL: RefCell<Vec<usize>> = const { RefCell::new(Vec::new()) };
- }
- fn app() -> Element {
- let mut count = use_signal(|| 0);
- let memorized = use_memo(move || dbg!(count() * 2));
- use_memo(move || {
- println!("reading doubled");
- let doubled = memorized();
- VEC_SIGNAL.with_borrow_mut(|v| v.push(doubled))
- });
- // Writing to count many times in a row should not cause the memo to update other subscribers multiple times
- use_hook(move || {
- for _ in 0..10 {
- count += 1;
- // Reading the memo each time will trigger the memo to rerun immediately, but the VEC_SIGNAL should still only rerun once
- println!("doubled {memorized}");
- }
- });
- rsx! {}
- }
- let mut dom = VirtualDom::new(app);
- dom.rebuild_in_place();
- tokio::select! {
- _ = dom.wait_for_work() => {},
- _ = tokio::time::sleep(std::time::Duration::from_millis(100)) => {}
- };
- dom.render_immediate(&mut dioxus::dioxus_core::NoOpMutations);
- assert_eq!(VEC_SIGNAL.with(|v| v.borrow().clone()), vec![0, 20]);
- }
|