ratatui_kit/hooks/
use_effect.rs

1use futures::{FutureExt, future::BoxFuture};
2use std::{hash::Hash, task::Poll};
3
4use crate::{Hook, UseMemo, hash_deps};
5
6mod private {
7    pub trait Sealed {}
8    impl Sealed for crate::Hooks<'_, '_> {}
9}
10
11pub trait UseEffect: private::Sealed {
12    /// 注册同步副作用,依赖变化时自动执行,适合监听状态变化、同步校验等。
13    fn use_effect<F, D>(&mut self, f: F, deps: D)
14    where
15        F: FnOnce(),
16        D: Hash;
17
18    /// 注册异步副作用,依赖变化时自动执行,适合异步校验、异步请求等。
19    fn use_async_effect<F, D>(&mut self, f: F, deps: D)
20    where
21        F: Future<Output = ()> + Send + 'static,
22        D: Hash;
23}
24
25#[derive(Default)]
26pub struct UseAsyncEffectImpl {
27    f: Option<BoxFuture<'static, ()>>,
28    deps_hash: u64,
29}
30
31impl Hook for UseAsyncEffectImpl {
32    fn poll_change(
33        mut self: std::pin::Pin<&mut Self>,
34        cx: &mut std::task::Context,
35    ) -> std::task::Poll<()> {
36        if let Some(future) = self.f.as_mut()
37            && future.as_mut().poll(cx).is_ready() {
38                self.f = None;
39            }
40        Poll::Pending
41    }
42}
43
44impl UseEffect for crate::Hooks<'_, '_> {
45    fn use_effect<F, D>(&mut self, f: F, deps: D)
46    where
47        F: FnOnce(),
48        D: Hash,
49    {
50        self.use_memo(f, deps)
51    }
52
53    fn use_async_effect<F, D>(&mut self, f: F, deps: D)
54    where
55        F: Future<Output = ()> + Send + 'static,
56        D: Hash,
57    {
58        let dep_hash = hash_deps(deps);
59        let hook = self.use_hook(UseAsyncEffectImpl::default);
60
61        if hook.deps_hash != dep_hash {
62            hook.f = Some(f.boxed());
63            hook.deps_hash = dep_hash;
64        }
65    }
66}