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