hooks_yew/
component.rs

1use std::{cell::RefCell, pin::Pin, rc::Rc, task::Poll};
2
3use hooks::{dyn_hook, HookPollNextUpdate};
4use yew::{Component, Html, Properties};
5
6pub type DynHookComponent<Props> = dyn_hook![ for<'a> (&'a Props) -> Html ];
7
8pub struct PinBoxDynHookComponent<Props> {
9    hook: RefCell<Pin<Box<DynHookComponent<Props>>>>,
10    abort_control: Option<Rc<()>>,
11}
12
13impl<Props> PinBoxDynHookComponent<Props> {
14    #[inline]
15    pub fn new(hook: Pin<Box<DynHookComponent<Props>>>) -> Self {
16        Self {
17            hook: RefCell::new(hook),
18            abort_control: None,
19        }
20    }
21}
22
23impl<Props: 'static + Properties> PinBoxDynHookComponent<Props> {
24    pub fn view(&self, props: &Props) -> Html {
25        let mut hook = self.hook.borrow_mut();
26
27        let hook = hook.as_mut();
28
29        hook.erased_use_hook((props,))
30    }
31
32    pub fn rendered<COMP: Component<Message = bool>>(
33        &mut self,
34        ctx: &yew::Context<COMP>,
35        mut get_hook: impl FnMut(&COMP) -> &Self + 'static,
36    ) {
37        let weak = if let Some(ac) = &self.abort_control {
38            if Rc::weak_count(ac) == 0 && Rc::strong_count(ac) == 1 {
39                Some(Rc::downgrade(ac))
40            } else {
41                None
42            }
43        } else {
44            let abort_control = Rc::new(());
45            let weak = Rc::downgrade(&abort_control);
46            self.abort_control = Some(abort_control);
47            Some(weak)
48        };
49
50        if let Some(mut weak) = weak {
51            let scope = ctx.link();
52            let s = scope.clone();
53
54            scope.send_future(std::future::poll_fn(move |cx| {
55                if weak.strong_count() == 0 {
56                    return Poll::Ready(false);
57                }
58
59                let comp = s.get_component().unwrap();
60                let mut hook = get_hook(&comp).hook.borrow_mut();
61                let hook = hook.as_mut();
62                let res =
63                    <DynHookComponent<Props> as HookPollNextUpdate>::poll_next_update(hook, cx);
64
65                if res.is_ready() {
66                    std::mem::take(&mut weak);
67                }
68
69                res
70            }));
71        }
72    }
73
74    #[inline]
75    pub fn changed(&mut self) -> bool {
76        self.abort_control.take();
77        true
78    }
79}