dioxus_hooks/
use_reactive.rs1use dioxus_signals::{Readable, Writable};
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 use warnings::Warning;
114 dioxus_signals::warnings::signal_read_and_write_in_reactive_scope::allow(|| {
117 dioxus_signals::warnings::signal_write_in_component_body::allow(|| {
118 last_state.set(non_reactive_data.out())
119 })
120 });
121 }
122 move || closure(last_state())
123}
124
125#[doc = include_str!("../docs/rules_of_hooks.md")]
141#[macro_export]
142macro_rules! use_reactive {
143 (|| $($rest:tt)*) => { use_reactive( (), move |_| $($rest)* ) };
144 (| $($args:tt),* | $($rest:tt)*) => {
145 use_reactive(
146 ($(&$args),*),
147 move |($($args),*)| $($rest)*
148 )
149 };
150}