1use crate::runtime::RUNTIME;
2
3pub fn create_effect<F>(f: F)
4where
5 F: Fn() + 'static,
6{
7 let effect_id = RUNTIME.with(|rt| rt.borrow_mut().register_effect(f));
8 run_effect(effect_id);
9}
10
11pub(crate) fn run_effect(id: usize) {
12 RUNTIME.with(|rt| {
13 let prev = rt.borrow_mut().set_current_effect(Some(id));
14 let effect_fn = rt.borrow().clone_effect(id);
15
16 if let Some(f) = effect_fn {
17 f();
18 }
19
20 rt.borrow_mut().set_current_effect(prev);
21 });
22}
23
24pub(crate) fn flush_effects() {
25 loop {
26 let effect_id = RUNTIME.with(|rt| rt.borrow_mut().pop_pending_effect());
27 match effect_id {
28 Some(id) => run_effect(id),
29 None => break,
30 }
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use crate::signal::create_signal;
38 use std::cell::RefCell;
39 use std::rc::Rc;
40
41 #[test]
42 fn test_effect_runs_immediately() {
43 let ran = Rc::new(RefCell::new(false));
44 let ran_clone = ran.clone();
45
46 create_effect(move || {
47 *ran_clone.borrow_mut() = true;
48 });
49
50 assert!(*ran.borrow());
51 }
52
53 #[test]
54 fn test_effect_auto_run() {
55 let (count, set_count) = create_signal(0);
56 let effect_ran = Rc::new(RefCell::new(0));
57 let effect_ran_clone = effect_ran.clone();
58
59 create_effect(move || {
60 let _ = count.get();
61 *effect_ran_clone.borrow_mut() += 1;
62 });
63
64 assert_eq!(*effect_ran.borrow(), 1);
65 set_count.set(1);
66 assert_eq!(*effect_ran.borrow(), 2);
67 }
68
69 #[test]
70 fn test_effect_only_runs_when_tracked_signal_changes() {
71 let (count, set_count) = create_signal(0);
72 let (other, _set_other) = create_signal(100);
73 let effect_ran = Rc::new(RefCell::new(0));
74 let effect_ran_clone = effect_ran.clone();
75
76 create_effect(move || {
77 let _ = count.get();
78 let _ = other.get_untracked();
79 *effect_ran_clone.borrow_mut() += 1;
80 });
81
82 assert_eq!(*effect_ran.borrow(), 1);
83
84 set_count.set(1);
85 assert_eq!(*effect_ran.borrow(), 2);
86
87 set_count.set(2);
88 assert_eq!(*effect_ran.borrow(), 3);
89 }
90
91 #[test]
92 fn test_multiple_effects() {
93 let (count, set_count) = create_signal(0);
94 let effect1_ran = Rc::new(RefCell::new(0));
95 let effect2_ran = Rc::new(RefCell::new(0));
96
97 let e1 = effect1_ran.clone();
98 let c1 = count.clone();
99 create_effect(move || {
100 let _ = c1.get();
101 *e1.borrow_mut() += 1;
102 });
103
104 let e2 = effect2_ran.clone();
105 create_effect(move || {
106 let _ = count.get();
107 *e2.borrow_mut() += 1;
108 });
109
110 assert_eq!(*effect1_ran.borrow(), 1);
111 assert_eq!(*effect2_ran.borrow(), 1);
112
113 set_count.set(1);
114
115 assert_eq!(*effect1_ran.borrow(), 2);
116 assert_eq!(*effect2_ran.borrow(), 2);
117 }
118}