-
I've looked around and haven't found anything exactly like this, though the discussion on leptos server signals was sort of close. I was able to get the websocket server fns in 0.8 working great, but it results in a flash of content or a loading state on first load with an SSR app, where what I'd like is to use a Resource so that the initial value is serialized and rendered directly to HTML and then after hydration the websocket can take over and update the value. What's the best approach for this? This is what I have, and it seems to work, but if there's a cleaner or more idiomatic method, I'd love to know! I've never seen the skeleton ever appear, so this feels overkill? Also not sure how best to handle derived signals or slices properly without sticking the whole component down under the suspense. I also tried moving the RwSignal up and having the resources just set it when it finished, but this didn't result in the pre-rendered SSR html I was aiming for. let initial_status = Resource::new(
|| (),
|_| async {
let status_res = get_status().await;
match status_res {
Ok(status) => status,
Err(err) => {
logging::error!("failed to get status: {err}");
Status::default()
}
}
},
);
// Update status on a timer over a websocket.
let status = RwSignal::new(None);
if cfg!(feature = "hydrate") {
spawn_status_ws(status);
}
// The reason for this Suspense/Nested Content structure is to because I had hydration errors due to lots of derived signals from the resource/websocket signal
view! {
<Suspense fallback=ContentSkeleton>
{Suspend::new(async move {
let initial_status = initial_status.await;
let status = Memo::new(move |_| status.get().unwrap_or(initial_status.clone()));
view! { <Content status /> }
})}
</Suspense>
} |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 3 replies
-
Is this more inline with how things are intended? I saw some examples with a similar pattern let initial_status = Resource::new(
|| (),
|_| async {
let status_res = get_status().await;
match status_res {
Ok(status) => status,
Err(err) => {
logging::error!("failed to get status: {err}");
Status::default()
}
}
},
);
// Update status on a timer over a websocket.
let status = Resource::new(
|| (),
move |_| async move {
let status = RwSignal::new(initial_status.await);
if cfg!(feature = "hydrate") {
spawn_status_ws(status);
}
status
}
); And from there just treating status like a normal resource |
Beta Was this translation helpful? Give feedback.
-
You can mutate resources just like you can mutate |
Beta Was this translation helpful? Give feedback.
-
I'm not sure I quite understand that you can mutate resources like signals since Resource doesn't implement write, however I did find this as an acceptable implementation let status = Resource::new(
|| (),
async |_| {
let initial_status = get_status().await.unwrap_or_default();
RwSignal::new(initial_status)
},
);
if cfg!(feature = "hydrate") {
status.map(|status| spawn_status_ws(status));
} |
Beta Was this translation helpful? Give feedback.
You can mutate resources just like you can mutate
RwSignal
, so I'm not sure there's really ever a need to synchronize between anRwSignal
and aResource
, but if that's what you want to do then the ways you're doing it seem fine. I don't think there's an established pattern for how to do this well.