yew/functional/hooks/use_prepared_state/
feat_ssr.rs1use 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}