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