Skip to main content
This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

yew/functional/hooks/use_prepared_state/
feat_ssr.rs

1//! The server-side rendering variant. This is used for server side rendering.
2
3use std::marker::PhantomData;
4use std::rc::Rc;
5
6use serde::Serialize;
7use serde::de::DeserializeOwned;
8
9use super::PreparedStateBase;
10use crate::functional::{Hook, HookContext, use_memo, use_state};
11use crate::platform::spawn_local;
12use crate::suspense::{Suspension, SuspensionResult};
13
14#[doc(hidden)]
15pub fn use_prepared_state<T, D, F>(
16    deps: D,
17    f: F,
18) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
19where
20    D: Serialize + DeserializeOwned + PartialEq + 'static,
21    T: Serialize + DeserializeOwned + 'static,
22    F: FnOnce(Rc<D>) -> T,
23{
24    struct HookProvider<T, D, F>
25    where
26        D: Serialize + DeserializeOwned + PartialEq + 'static,
27        T: Serialize + DeserializeOwned + 'static,
28        F: FnOnce(Rc<D>) -> T,
29    {
30        deps: D,
31        f: F,
32    }
33
34    impl<T, D, F> Hook for HookProvider<T, D, F>
35    where
36        D: Serialize + DeserializeOwned + PartialEq + 'static,
37        T: Serialize + DeserializeOwned + 'static,
38        F: FnOnce(Rc<D>) -> T,
39    {
40        type Output = SuspensionResult<Option<Rc<T>>>;
41
42        fn run(self, ctx: &mut HookContext) -> Self::Output {
43            let f = self.f;
44            let deps = Rc::new(self.deps);
45
46            let state = {
47                let deps = deps.clone();
48                use_memo((), move |_| f(deps)).run(ctx)
49            };
50
51            let state = PreparedStateBase {
52                state: Some(state),
53                deps: Some(deps),
54                #[cfg(feature = "hydration")]
55                has_buf: true,
56                _marker: PhantomData,
57            };
58
59            let state =
60                ctx.next_prepared_state(|_re_render, _| -> PreparedStateBase<T, D> { state });
61
62            Ok(state.state.clone())
63        }
64    }
65
66    HookProvider::<T, D, F> { deps, f }
67}
68
69#[doc(hidden)]
70pub fn use_prepared_state_with_suspension<T, D, F, U>(
71    deps: D,
72    f: F,
73) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
74where
75    D: Serialize + DeserializeOwned + PartialEq + 'static,
76    T: Serialize + DeserializeOwned + 'static,
77    F: FnOnce(Rc<D>) -> U,
78    U: 'static + Future<Output = T>,
79{
80    struct HookProvider<T, D, F, U>
81    where
82        D: Serialize + DeserializeOwned + PartialEq + 'static,
83        T: Serialize + DeserializeOwned + 'static,
84        F: FnOnce(Rc<D>) -> U,
85        U: 'static + Future<Output = T>,
86    {
87        deps: D,
88        f: F,
89    }
90
91    impl<T, D, F, U> Hook for HookProvider<T, D, F, U>
92    where
93        D: Serialize + DeserializeOwned + PartialEq + 'static,
94        T: Serialize + DeserializeOwned + 'static,
95        F: FnOnce(Rc<D>) -> U,
96        U: 'static + Future<Output = T>,
97    {
98        type Output = SuspensionResult<Option<Rc<T>>>;
99
100        fn run(self, ctx: &mut HookContext) -> Self::Output {
101            let f = self.f;
102            let deps = Rc::new(self.deps);
103
104            let result = use_state(|| {
105                let (s, handle) = Suspension::new();
106                (Err(s), Some(handle))
107            })
108            .run(ctx);
109
110            {
111                let deps = deps.clone();
112                let result = result.clone();
113                use_state(move || {
114                    let state_f = f(deps.clone());
115
116                    spawn_local(async move {
117                        let state = state_f.await;
118                        result.set((Ok(Rc::new(state)), None));
119                    })
120                })
121                .run(ctx);
122            }
123
124            let state = result.0.clone()?;
125
126            let state = PreparedStateBase {
127                state: Some(state),
128                deps: Some(deps),
129                #[cfg(feature = "hydration")]
130                has_buf: true,
131                _marker: PhantomData,
132            };
133
134            let state =
135                ctx.next_prepared_state(|_re_render, _| -> PreparedStateBase<T, D> { state });
136
137            Ok(state.state.clone())
138        }
139    }
140
141    HookProvider::<T, D, F, U> { deps, f }
142}