dioxus_hooks/
use_reactive.rs1use dioxus_signals::{ReadableExt, WritableExt};
2
3use crate::use_signal;
4
5#[rustversion::attr(
7    since(1.78.0),
8    diagnostic::on_unimplemented(
9        message = "`Dependency` is not implemented for `{Self}`",
10        label = "Dependency",
11        note = "Dependency is automatically implemented for all tuples with less than 8 references to element that implement `PartialEq` and `Clone`. For example, `(&A, &B, &C)` implements `Dependency` automatically as long as `A`, `B`, and `C` implement `PartialEq` and `Clone`.",
12    )
13)]
14pub trait Dependency: Sized + Clone {
15    type Out: Clone + PartialEq + 'static;
17    fn out(&self) -> Self::Out;
19    fn changed(&self, other: &Self::Out) -> bool {
21        self.out() != *other
22    }
23}
24
25impl Dependency for () {
26    type Out = ();
27    fn out(&self) -> Self::Out {}
28}
29
30#[rustversion::attr(
32    since(1.78.0),
33    diagnostic::on_unimplemented(
34        message = "`DependencyElement` is not implemented for `{Self}`",
35        label = "dependency element",
36        note = "DependencyElement is automatically implemented for types that implement `PartialEq` and `Clone`",
37    )
38)]
39pub trait DependencyElement: 'static + PartialEq + Clone {}
40impl<T> DependencyElement for T where T: 'static + PartialEq + Clone {}
41
42impl<A: DependencyElement> Dependency for &A {
43    type Out = A;
44    fn out(&self) -> Self::Out {
45        (*self).clone()
46    }
47}
48
49macro_rules! impl_dep {
50    (
51        $($el:ident=$name:ident $other:ident,)*
52    ) => {
53        impl< $($el),* > Dependency for ($(&$el,)*)
54        where
55            $(
56                $el: DependencyElement
57            ),*
58        {
59            type Out = ($($el,)*);
60
61            fn out(&self) -> Self::Out {
62                let ($($name,)*) = self;
63                ($((*$name).clone(),)*)
64            }
65
66            fn changed(&self, other: &Self::Out) -> bool {
67                let ($($name,)*) = self;
68                let ($($other,)*) = other;
69                $(
70                    if *$name != $other {
71                        return true;
72                    }
73                )*
74                false
75            }
76        }
77    };
78}
79
80impl_dep!(A = a1 a2,);
81impl_dep!(A = a1 a2, B = b1 b2,);
82impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2,);
83impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2,);
84impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2,);
85impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2, F = f1 f2,);
86impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2, F = f1 f2, G = g1 g2,);
87impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2, F = f1 f2, G = g1 g2, H = h1 h2,);
88
89#[doc = include_str!("../docs/rules_of_hooks.md")]
103pub fn use_reactive<O, D: Dependency>(
104    non_reactive_data: D,
105    mut closure: impl FnMut(D::Out) -> O + 'static,
106) -> impl FnMut() -> O + 'static {
107    let mut first_run = false;
108    let mut last_state = use_signal(|| {
109        first_run = true;
110        non_reactive_data.out()
111    });
112    if !first_run && non_reactive_data.changed(&*last_state.peek()) {
113        last_state.set(non_reactive_data.out())
114    }
115    move || closure(last_state())
116}
117
118#[doc = include_str!("../docs/rules_of_hooks.md")]
134#[macro_export]
135macro_rules! use_reactive {
136    (|| $($rest:tt)*) => { use_reactive( (), move |_| $($rest)* ) };
137    (| $($args:tt),* | $($rest:tt)*) => {
138        use_reactive(
139            ($(&$args),*),
140            move |($($args),*)| $($rest)*
141        )
142    };
143}