1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! # Hooks
//!
//! **Hooks** are special functions that let you tap into Freya's reactivity and lifecycle system.
//! They can **only** be called at the top level of your component's `render` method (not inside event handlers, loops, or conditionals).
//!
//! Hooks are always prefixed with `use_`, for example: [`use_animation`](crate::animation::use_animation), [`use_state`](crate::prelude::use_state), etc.
//!
//! ## Rules of Hooks
//!
//! Hooks are not ordinary functions. To ensure correct behavior, follow these rules:
//!
//! ### 1. Only call hooks at the top level of your `render` method
//!
//! Hooks must always be called in the same order on every render.
//!
//! ❌ **Incorrect:**
//! ```rust
//! # use freya::prelude::*;
//! #[derive(PartialEq)]
//! struct MyComponent(bool);
//! impl Component for MyComponent {
//! fn render(&self) -> impl IntoElement {
//! if self.0 {
//! let state = use_state(|| self.0);
//! // ...
//! }
//! rect()
//! }
//! }
//! ```
//!
//! ✅ **Correct:**
//! ```rust
//! # use freya::prelude::*;
//! #[derive(PartialEq)]
//! struct MyComponent(bool);
//! impl Component for MyComponent {
//! fn render(&self) -> impl IntoElement {
//! let state = use_state(|| self.0);
//! rect()
//! }
//! }
//! ```
//!
//! Or, move state up to the parent component for even simpler code:
//! ```rust
//! # use freya::prelude::*;
//! #[derive(PartialEq)]
//! struct MyComponent(bool);
//! impl Component for MyComponent {
//! fn render(&self) -> impl IntoElement {
//! rect()
//! }
//! }
//! ```
//!
//! ### 2. Only call hooks inside `render` methods
//!
//! Hooks **cannot** be called inside event handlers, async blocks, or outside of components.
//!
//! ❌ **Incorrect:**
//! ```rust
//! # use freya::prelude::*;
//! #[derive(PartialEq)]
//! struct MyComponent;
//! impl Component for MyComponent {
//! fn render(&self) -> impl IntoElement {
//! let on_mouse_up = |_| {
//! let state = use_state(|| false); // ❌ Not allowed here
//! };
//! rect().on_mouse_up(on_mouse_up).child("Hello, World!")
//! }
//! }
//! ```
//!
//! ✅ **Correct:**
//! ```rust
//! # use freya::prelude::*;
//! #[derive(PartialEq)]
//! struct MyComponent;
//! impl Component for MyComponent {
//! fn render(&self) -> impl IntoElement {
//! let mut state = use_state(|| false);
//! let on_mouse_up = move |_| {
//! state.set(true);
//! };
//! rect().on_mouse_up(on_mouse_up).child("Hello, World!")
//! }
//! }
//! ```
//!
//! ### 3. Do not call hooks inside loops
//!
//! The number of hook calls must not change between renders.
//!
//! ❌ **Incorrect:**
//! ```rust
//! # use freya::prelude::*;
//! #[derive(PartialEq)]
//! struct MyComponent;
//! impl Component for MyComponent {
//! fn render(&self) -> impl IntoElement {
//! for i in 0..5 {
//! let state = use_state(|| i); // ❌ Not allowed in a loop
//! }
//! rect().child("Hello, World!")
//! }
//! }
//! ```
//!
//! ✅ **Correct:**
//! ```rust
//! # use freya::prelude::*;
//! #[derive(PartialEq)]
//! struct MyComponent;
//! impl Component for MyComponent {
//! fn render(&self) -> impl IntoElement {
//! let state = use_state(|| (0..5).collect::<Vec<_>>());
//! rect().child("Hello, World!")
//! }
//! }
//! ```