Skip to main content

ratatui_kit/hooks/
mod.rs

1// hooks 模块:为组件提供响应式状态、副作用、事件、上下文等能力,灵感来源于 React Hooks。
2//
3// ## 如何实现一个规范的自定义 hook
4//
5// 1. 定义一个实现 [`Hook`] trait 的结构体,管理自己的状态和生命周期。
6// 2. 在 `poll_change`、`pre_component_update`、`post_component_update`、`pre_component_draw`、`post_component_draw` 等方法中实现副作用或状态逻辑。
7// 3. 提供 trait(如 `pub trait UseXxx`)暴露给用户,trait 方法通过 `Hooks::use_hook` 注册/获取 hook 实例。
8// 4. 推荐通过 `private::Sealed` 限制 trait 只对框架内部实现。
9//
10// ```rust
11// // 1. 定义 hook 状态结构体
12// pub struct MyHook { ... }
13// impl Hook for MyHook { ... }
14//
15// // 2. 提供 trait API
16// pub trait UseMyHook: private::Sealed {
17//     fn use_my_hook(&mut self, ...) -> ...;
18// }
19// impl UseMyHook for Hooks<'_, '_> {
20//     fn use_my_hook(&mut self, ...) -> ... {
21//         self.use_hook(|| MyHook { ... })
22//     }
23// }
24// ```
25//
26// 这样可保证 hook 生命周期、类型安全和复用性。
27
28#![allow(unused)]
29use crate::{
30    context::ContextStack,
31    render::{ComponentDrawer, ComponentUpdater},
32};
33use std::{
34    any::Any,
35    task::{Context, Poll},
36};
37mod use_context;
38pub use use_context::*;
39mod use_input;
40pub use use_input::*;
41mod use_future;
42pub use use_future::*;
43mod use_state;
44pub use use_state::*;
45mod use_memo;
46pub use use_memo::*;
47mod use_effect;
48pub use use_effect::*;
49mod use_async_state;
50pub use use_async_state::*;
51mod use_insert_before;
52pub use use_insert_before::*;
53mod use_size;
54pub use use_size::*;
55mod use_exit;
56pub use use_exit::*;
57mod use_on_drop;
58pub use use_on_drop::*;
59
60#[cfg(feature = "router")]
61mod use_router;
62#[cfg(feature = "router")]
63pub use use_router::*;
64
65// 所有自定义 hook 的 trait 基础,定义生命周期相关回调。
66//
67// - `poll_change`:异步/响应式副作用轮询,适合 use_future/use_effect 等。
68// - `pre_component_update/post_component_update`:组件更新前后钩子。
69// - `pre_component_draw/post_component_draw`:组件渲染前后钩子。
70//
71// 通常无需手动实现,除非自定义复杂 hook。
72pub trait Hook: Unpin {
73    fn poll_change(&mut self, _cx: &mut Context) -> Poll<()> {
74        Poll::Pending
75    }
76
77    fn pre_component_update(&mut self, _updater: &mut ComponentUpdater) {}
78    fn post_component_update(&mut self, _updater: &mut ComponentUpdater) {}
79
80    fn pre_component_draw(&mut self, _drawer: &mut ComponentDrawer) {}
81    fn post_component_draw(&mut self, _drawer: &mut ComponentDrawer) {}
82
83    fn on_drop(&mut self) {}
84}
85
86pub(crate) trait AnyHook: Hook {
87    fn any_self_mut(&mut self) -> &mut dyn Any;
88}
89
90impl<T: Hook + 'static> AnyHook for T {
91    fn any_self_mut(&mut self) -> &mut dyn Any {
92        self
93    }
94}
95
96impl Hook for Vec<Box<dyn AnyHook>> {
97    fn poll_change(&mut self, _cx: &mut Context) -> Poll<()> {
98        let mut is_ready = false;
99        for hook in self.iter_mut() {
100            if hook.poll_change(_cx).is_ready() {
101                is_ready = true;
102            }
103        }
104
105        if is_ready {
106            Poll::Ready(())
107        } else {
108            Poll::Pending
109        }
110    }
111
112    fn pre_component_update(&mut self, _updater: &mut ComponentUpdater) {
113        for hook in self.iter_mut() {
114            hook.pre_component_update(_updater);
115        }
116    }
117
118    fn post_component_update(&mut self, _updater: &mut ComponentUpdater) {
119        for hook in self.iter_mut() {
120            hook.post_component_update(_updater);
121        }
122    }
123
124    fn pre_component_draw(&mut self, _updater: &mut ComponentDrawer) {
125        for hook in self.iter_mut() {
126            hook.pre_component_draw(_updater);
127        }
128    }
129
130    fn post_component_draw(&mut self, _updater: &mut ComponentDrawer) {
131        for hook in self.iter_mut() {
132            hook.post_component_draw(_updater);
133        }
134    }
135
136    fn on_drop(&mut self) {
137        for hook in self.iter_mut() {
138            hook.on_drop();
139        }
140    }
141}
142
143// hooks 管理器,负责组件内所有 hook 的注册、索引和生命周期。
144//
145// - 通过 `use_hook` 注册/获取 hook 实例,保证顺序和类型安全。
146// - 支持 context 注入、首次更新标记等。
147// - 用户无需手动创建,框架自动管理。
148//
149// # 示例
150// ```rust
151// let mut state = hooks.use_state(|| 0);
152// let ctx = hooks.use_context::<MyType>();
153// ```
154pub struct Hooks<'a, 'b: 'a> {
155    hooks: &'a mut Vec<Box<dyn AnyHook>>,
156    first_update: bool,
157    hook_index: usize,
158    pub(crate) context: Option<&'a ContextStack<'b>>,
159}
160
161impl<'a> Hooks<'a, '_> {
162    pub(crate) fn new(hooks: &'a mut Vec<Box<dyn AnyHook>>, first_update: bool) -> Self {
163        Self {
164            hooks,
165            first_update,
166            hook_index: 0,
167            context: None,
168        }
169    }
170
171    pub fn with_context_stack<'c, 'd>(
172        &'c mut self,
173        context: &'c ContextStack<'d>,
174    ) -> Hooks<'c, 'd> {
175        Hooks {
176            hooks: self.hooks,
177            first_update: self.first_update,
178            hook_index: self.hook_index,
179            context: Some(context),
180        }
181    }
182
183    pub fn use_hook<F, H>(&mut self, f: F) -> &mut H
184    where
185        F: FnOnce() -> H,
186        H: Hook + Unpin + 'static,
187    {
188        if self.first_update {
189            self.hooks.push(Box::new(f()));
190        }
191        let idx = self.hook_index;
192        self.hook_index += 1;
193
194        self.hooks
195            .get_mut(idx)
196            .and_then(|hook| hook.any_self_mut().downcast_mut::<H>())
197            .expect("Hook type mismatch, ensure the hook is of the correct type")
198    }
199}