dioxus_use_computed/hooks/
use_computed.rs1use std::{cell::RefCell, rc::Rc};
2
3use dioxus_lib::prelude::{use_hook, use_signal, ReadOnlySignal, Readable, Writable};
4mod warnings {
5 pub use warnings::Warning;
6}
7pub use warnings::Warning;
8
9
10pub fn use_computed<T: 'static + Clone, D: PartialEq + 'static>(
16 deps: D,
17 init: impl FnOnce() -> T,
18) -> T {
19 use_computed_with_prev(deps, |_| init())
20}
21
22pub fn use_computed_with_prev<T: 'static + Clone, D: PartialEq + 'static>(
29 deps: D,
30 init: impl FnOnce(Option<T>) -> T,
31) -> T {
32 struct Memoized<T, D> {
33 value: T,
34 deps: D,
35 }
36 let memo_signal = use_hook(|| Rc::new(RefCell::new(None::<Memoized<T, D>>)));
37 let mut memo = memo_signal.borrow_mut();
38
39 let deps_have_changed = memo.as_ref().map(|memo| &memo.deps) != Some(&deps);
40
41 let new_value = if deps_have_changed {
42 let prev_value = memo.take().map(|memo| memo.value);
43 Some(init(prev_value))
44 } else {
45 None
46 };
47
48 if let Some(new_value) = new_value {
49 let new_memoized_value = Memoized {
50 value: new_value,
51 deps,
52 };
53 *memo = Some(new_memoized_value);
54 }
55
56 memo.as_ref().unwrap().value.clone()
57}
58
59pub fn use_computed_signal<T: 'static, D: PartialEq + Clone + 'static>(
65 deps: D,
66 init: impl Fn() -> T,
67) -> ReadOnlySignal<T> {
68 use_computed_signal_with_prev(deps, move |_| init())
69}
70
71pub fn use_computed_signal_with_prev<T: 'static, D: PartialEq + Clone + 'static>(
79 deps: D,
80 init: impl Fn(Option<&mut T>) -> T,
81) -> ReadOnlySignal<T> {
82 let mut deps_signal = use_signal::<D>(|| deps.clone());
83 let mut value_signal = use_signal::<T>(|| init(None));
84
85 let deps_have_changed = *deps_signal.peek() != deps;
86
87 if deps_have_changed {
88 dioxus_lib::prelude::warnings::signal_write_in_component_body::allow(|| {
89 let mut memoized_deps = deps_signal.write();
90 let mut memoized_value = value_signal.write();
91
92 let new_value = init(Some(&mut *memoized_value));
93
94 *memoized_value = new_value;
95 *memoized_deps = deps;
96 });
97 }
98
99 value_signal.into()
100}