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