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            if future.as_mut().poll(cx).is_ready() {
38                self.f = None;
39            }
40        }
41        Poll::Pending
42    }
43}
44
45impl UseEffect for crate::Hooks<'_, '_> {
46    fn use_effect<F, D>(&mut self, f: F, deps: D)
47    where
48        F: FnOnce(),
49        D: Hash,
50    {
51        self.use_memo(f, deps)
52    }
53
54    fn use_async_effect<F, D>(&mut self, f: F, deps: D)
55    where
56        F: Future<Output = ()> + Send + 'static,
57        D: Hash,
58    {
59        let dep_hash = hash_deps(deps);
60        let hook = self.use_hook(UseAsyncEffectImpl::default);
61
62        if hook.deps_hash != dep_hash {
63            hook.f = Some(f.boxed());
64            hook.deps_hash = dep_hash;
65        }
66    }
67}