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    pin::Pin,
36    task::{Context, Poll},
37};
38mod use_context;
39pub use use_context::*;
40mod use_events;
41pub use use_events::*;
42mod use_future;
43pub use use_future::*;
44mod use_state;
45pub use use_state::*;
46mod use_memo;
47pub use use_memo::*;
48mod use_effect;
49pub use use_effect::*;
50mod use_insert_before;
51pub use use_insert_before::*;
52mod use_size;
53pub use use_size::*;
54mod use_exit;
55pub use use_exit::*;
56mod use_on_drop;
57pub use use_on_drop::*;
58
59#[cfg(feature = "router")]
60mod use_router;
61#[cfg(feature = "router")]
62pub use use_router::*;
63
64/// 所有自定义 hook 的 trait 基础,定义生命周期相关回调。
65///
66/// - `poll_change`:异步/响应式副作用轮询,适合 use_future/use_effect 等。
67/// - `pre_component_update/post_component_update`:组件更新前后钩子。
68/// - `pre_component_draw/post_component_draw`:组件渲染前后钩子。
69///
70/// 通常无需手动实现,除非自定义复杂 hook。
71pub trait Hook: Unpin + Send {
72    fn poll_change(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<()> {
73        Poll::Pending
74    }
75
76    fn pre_component_update(&mut self, _updater: &mut ComponentUpdater) {}
77    fn post_component_update(&mut self, _updater: &mut ComponentUpdater) {}
78
79    fn pre_component_draw(&mut self, _drawer: &mut ComponentDrawer) {}
80    fn post_component_draw(&mut self, _drawer: &mut ComponentDrawer) {}
81
82    fn on_drop(&mut self) {}
83}
84
85pub(crate) trait AnyHook: Hook {
86    fn any_self_mut(&mut self) -> &mut dyn Any;
87}
88
89impl<T: Hook + 'static> AnyHook for T {
90    fn any_self_mut(&mut self) -> &mut dyn Any {
91        self
92    }
93}
94
95impl Hook for Vec<Box<dyn AnyHook>> {
96    fn poll_change(mut self: Pin<&mut Self>, _cx: &mut Context) -> Poll<()> {
97        let mut is_ready = false;
98        for hook in self.iter_mut() {
99            if Pin::new(&mut **hook).poll_change(_cx).is_ready() {
100                is_ready = true;
101            }
102        }
103
104        if is_ready {
105            Poll::Ready(())
106        } else {
107            Poll::Pending
108        }
109    }
110
111    fn pre_component_update(&mut self, _updater: &mut ComponentUpdater) {
112        for hook in self.iter_mut() {
113            hook.pre_component_update(_updater);
114        }
115    }
116
117    fn post_component_update(&mut self, _updater: &mut ComponentUpdater) {
118        for hook in self.iter_mut() {
119            hook.post_component_update(_updater);
120        }
121    }
122
123    fn pre_component_draw(&mut self, _updater: &mut ComponentDrawer) {
124        for hook in self.iter_mut() {
125            hook.pre_component_draw(_updater);
126        }
127    }
128
129    fn post_component_draw(&mut self, _updater: &mut ComponentDrawer) {
130        for hook in self.iter_mut() {
131            hook.post_component_draw(_updater);
132        }
133    }
134
135    fn on_drop(&mut self) {
136        for hook in self.iter_mut() {
137            hook.on_drop();
138        }
139    }
140}
141
142/// hooks 管理器,负责组件内所有 hook 的注册、索引和生命周期。
143///
144/// - 通过 `use_hook` 注册/获取 hook 实例,保证顺序和类型安全。
145/// - 支持 context 注入、首次更新标记等。
146/// - 用户无需手动创建,框架自动管理。
147///
148/// # 示例
149/// ```rust
150/// let mut state = hooks.use_state(|| 0);
151/// let ctx = hooks.use_context::<MyType>();
152/// ```
153pub struct Hooks<'a, 'b: 'a> {
154    hooks: &'a mut Vec<Box<dyn AnyHook>>,
155    first_update: bool,
156    hook_index: usize,
157    pub(crate) context: Option<&'a ContextStack<'b>>,
158}
159
160impl<'a> Hooks<'a, '_> {
161    pub(crate) fn new(hooks: &'a mut Vec<Box<dyn AnyHook>>, first_update: bool) -> Self {
162        Self {
163            hooks,
164            first_update,
165            hook_index: 0,
166            context: None,
167        }
168    }
169
170    pub fn with_context_stack<'c, 'd>(
171        &'c mut self,
172        context: &'c ContextStack<'d>,
173    ) -> Hooks<'c, 'd> {
174        Hooks {
175            hooks: self.hooks,
176            first_update: self.first_update,
177            hook_index: self.hook_index,
178            context: Some(context),
179        }
180    }
181
182    pub fn use_hook<F, H>(&mut self, f: F) -> &mut H
183    where
184        F: FnOnce() -> H,
185        H: Hook + Unpin + 'static,
186    {
187        if self.first_update {
188            self.hooks.push(Box::new(f()));
189        }
190        let idx = self.hook_index;
191        self.hook_index += 1;
192
193        self.hooks
194            .get_mut(idx)
195            .and_then(|hook| hook.any_self_mut().downcast_mut::<H>())
196            .expect("Hook type mismatch, ensure the hook is of the correct type")
197    }
198}