freya/_docs/
hooks.rs

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