use dioxus_lib::prelude::*;
use serde::{de::DeserializeOwned, Serialize};
use std::future::Future;
#[must_use = "Consider using `cx.spawn` to run a future without reading its value"]
pub fn use_server_future<T, F>(
mut future: impl FnMut() -> F + 'static,
) -> Result<Resource<T>, RenderError>
where
T: Serialize + DeserializeOwned + 'static,
F: Future<Output = T> + 'static,
{
#[cfg(feature = "server")]
let serialize_context = crate::html_storage::use_serialize_context();
#[cfg(feature = "server")]
let server_storage_entry = use_hook(|| serialize_context.create_entry());
#[cfg(feature = "web")]
let initial_web_result = use_hook(|| {
tracing::info!("First run of use_server_future");
std::rc::Rc::new(std::cell::RefCell::new(Some(
dioxus_web::take_server_data::<T>(),
)))
});
let resource = use_resource(move || {
#[cfg(feature = "server")]
let serialize_context = serialize_context.clone();
let user_fut = future();
#[cfg(feature = "web")]
let initial_web_result = initial_web_result.clone();
async move {
#[cfg(feature = "web")]
{
let initial = initial_web_result.borrow_mut().take();
match initial {
None => {}
Some(first_run) => {
match first_run {
Ok(Some(o)) => return o,
Ok(None) => {
tracing::trace!("Waiting for server data");
std::future::pending::<()>().await;
}
Err(_) => {}
}
}
}
}
let out = user_fut.await;
#[cfg(feature = "server")]
serialize_context.insert(server_storage_entry, &out);
#[allow(clippy::let_and_return)]
out
}
});
use_hook(|| {
let _ = resource.task().poll_now();
});
match resource.state().cloned() {
UseResourceState::Pending => {
let task = resource.task();
if !task.paused() {
return Err(suspend(task).unwrap_err());
}
Ok(resource)
}
_ => Ok(resource),
}
}