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 Render 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 Render 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 Render 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//! struct MyComponent;
65//! impl Render for MyComponent {
66//!     fn render(&self) -> impl IntoElement {
67//!         let onclick = |_| {
68//!             let state = use_state(|| false); // ❌ Not allowed here
69//!         };
70//!         rect().on_mouse_up(onclick).child("Hello, World!")
71//!     }
72//! }
73//! ```
74//!
75//! ✅ **Correct:**
76//! ```rust
77//! # use freya::prelude::*;
78//! struct MyComponent;
79//! impl Render for MyComponent {
80//!     fn render(&self) -> impl IntoElement {
81//!         let mut state = use_state(|| false);
82//!         let onclick = move |_| {
83//!             state.set(true);
84//!         };
85//!         rect().on_mouse_up(onclick).child("Hello, World!")
86//!     }
87//! }
88//! ```
89//!
90//! ### 3. Do not call hooks inside loops
91//!
92//! The number of hook calls must not change between renders.
93//!
94//! ❌ **Incorrect:**
95//! ```rust
96//! # use freya::prelude::*;
97//! struct MyComponent;
98//! impl Render for MyComponent {
99//!     fn render(&self) -> impl IntoElement {
100//!         for i in 0..5 {
101//!             let state = use_state(|| i); // ❌ Not allowed in a loop
102//!         }
103//!         rect().child("Hello, World!")
104//!     }
105//! }
106//! ```
107//!
108//! ✅ **Correct:**
109//! ```rust
110//! # use freya::prelude::*;
111//! struct MyComponent;
112//! impl Render for MyComponent {
113//!     fn render(&self) -> impl IntoElement {
114//!         let state = use_state(|| (0..5).collect::<Vec<_>>());
115//!         rect().child("Hello, World!")
116//!     }
117//! }
118//! ```