Skip to main content

react_rs_core/
effect.rs

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}