freya_core/lifecycle/
effect.rs

1use std::{
2    cell::RefCell,
3    rc::Rc,
4};
5
6use crate::{
7    prelude::{
8        State,
9        spawn,
10        use_hook,
11        use_reactive,
12    },
13    reactive_context::ReactiveContext,
14};
15
16pub struct Effect;
17
18impl Effect {
19    pub fn create(mut callback: impl FnMut() + 'static) {
20        let (rx, rc) = ReactiveContext::new_for_task();
21        spawn(async move {
22            loop {
23                ReactiveContext::run(rc.clone(), &mut callback);
24                rx.notified().await;
25            }
26        });
27    }
28
29    pub fn create_with_gen(mut callback: impl FnMut(usize) + 'static) {
30        let (rx, rc) = ReactiveContext::new_for_task();
31        spawn(async move {
32            let mut current_gen = 0;
33            loop {
34                ReactiveContext::run(rc.clone(), || callback(current_gen));
35                rx.notified().await;
36                current_gen += 1;
37            }
38        });
39    }
40
41    pub fn create_sync(mut callback: impl FnMut() + 'static) {
42        let (rx, rc) = ReactiveContext::new_for_task();
43        ReactiveContext::run(rc.clone(), &mut callback);
44        spawn(async move {
45            loop {
46                rx.notified().await;
47                ReactiveContext::run(rc.clone(), &mut callback);
48            }
49        });
50    }
51
52    pub fn create_after(callback: impl FnMut() + 'static) {
53        let (rx, rc) = ReactiveContext::new_for_task();
54        let callback = Rc::new(RefCell::new(callback));
55        spawn(async move {
56            loop {
57                let callback = callback.clone();
58                let rc = rc.clone();
59                spawn(async move {
60                    ReactiveContext::run(rc, &mut *callback.borrow_mut());
61                });
62                rx.notified().await;
63            }
64        });
65    }
66
67    pub fn create_value<T: 'static>(mut callback: impl FnMut() -> T + 'static) -> State<T> {
68        let (rx, rc) = ReactiveContext::new_for_task();
69        let mut state = State::create(ReactiveContext::run(rc.clone(), &mut callback));
70        spawn(async move {
71            let mut current_gen = 0;
72            loop {
73                if current_gen > 0 {
74                    state.set(ReactiveContext::run(rc.clone(), &mut callback));
75                }
76                rx.notified().await;
77                current_gen += 1;
78            }
79        });
80        state
81    }
82}
83
84/// Registers a callback that will run every time a [crate::lifecycle::state::State] which was [crate::lifecycle::state::State::read] inside, changes.
85pub fn use_side_effect(callback: impl FnMut() + 'static) {
86    use_hook(|| Effect::create(callback));
87}
88
89pub fn use_after_side_effect(callback: impl FnMut() + 'static) {
90    use_hook(|| Effect::create_after(callback));
91}
92
93pub fn use_side_effect_value<T: 'static>(callback: impl FnMut() -> T + 'static) -> State<T> {
94    use_hook(|| Effect::create_value(callback))
95}
96
97pub fn use_side_effect_with_deps<D: 'static + Clone + PartialEq>(
98    deps: &D,
99    mut callback: impl FnMut(&D) + 'static,
100) {
101    let deps = use_reactive(deps);
102    use_hook(move || {
103        Effect::create(move || {
104            let deps = deps.read();
105            callback(&deps)
106        })
107    });
108}