server_future.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. use dioxus::prelude::*;
  2. use serde::{de::DeserializeOwned, Serialize};
  3. use std::any::Any;
  4. use std::cell::Cell;
  5. use std::cell::Ref;
  6. use std::cell::RefCell;
  7. use std::fmt::Debug;
  8. use std::future::Future;
  9. use std::rc::Rc;
  10. use std::sync::Arc;
  11. /// A future that resolves to a value.
  12. ///
  13. /// This runs the future only once - though the future may be regenerated
  14. /// through the [`UseServerFuture::restart`] method.
  15. ///
  16. /// This is commonly used for components that cannot be rendered until some
  17. /// asynchronous operation has completed.
  18. ///
  19. /// Whenever the hooks dependencies change, the future will be re-evaluated.
  20. /// If a future is pending when the dependencies change, the previous future
  21. /// will be allowed to continue
  22. ///
  23. /// - dependencies: a tuple of references to values that are PartialEq + Clone
  24. #[must_use = "Consider using `cx.spawn` to run a future without reading its value"]
  25. pub fn use_server_future<T, F, D>(
  26. cx: &ScopeState,
  27. dependencies: D,
  28. future: impl FnOnce(D::Out) -> F,
  29. ) -> Option<&UseServerFuture<T>>
  30. where
  31. T: 'static + Serialize + DeserializeOwned + Debug,
  32. F: Future<Output = T> + 'static,
  33. D: UseFutureDep,
  34. {
  35. let state = cx.use_hook(move || UseServerFuture {
  36. update: cx.schedule_update(),
  37. needs_regen: Cell::new(true),
  38. value: Default::default(),
  39. task: Cell::new(None),
  40. dependencies: Vec::new(),
  41. });
  42. let first_run = { state.value.borrow().as_ref().is_none() && state.task.get().is_none() };
  43. #[cfg(not(feature = "ssr"))]
  44. {
  45. if first_run {
  46. match crate::html_storage::deserialize::take_server_data() {
  47. Some(data) => {
  48. tracing::trace!("Loaded {data:?} from server");
  49. *state.value.borrow_mut() = Some(Box::new(data));
  50. state.needs_regen.set(false);
  51. return Some(state);
  52. }
  53. None => {
  54. tracing::trace!("Failed to load from server... running future");
  55. }
  56. };
  57. }
  58. }
  59. if dependencies.clone().apply(&mut state.dependencies) || state.needs_regen.get() {
  60. // We don't need regen anymore
  61. state.needs_regen.set(false);
  62. // Create the new future
  63. let fut = future(dependencies.out());
  64. // Clone in our cells
  65. let value = state.value.clone();
  66. let schedule_update = state.update.clone();
  67. // Cancel the current future
  68. if let Some(current) = state.task.take() {
  69. cx.remove_future(current);
  70. }
  71. state.task.set(Some(cx.push_future(async move {
  72. let data;
  73. #[cfg(feature = "ssr")]
  74. {
  75. data = fut.await;
  76. if first_run {
  77. if let Err(err) = crate::prelude::server_context().push_html_data(&data) {
  78. tracing::error!("Failed to push HTML data: {}", err);
  79. };
  80. }
  81. }
  82. #[cfg(not(feature = "ssr"))]
  83. {
  84. data = fut.await;
  85. }
  86. *value.borrow_mut() = Some(Box::new(data));
  87. schedule_update();
  88. })));
  89. }
  90. if first_run {
  91. #[cfg(feature = "ssr")]
  92. {
  93. tracing::trace!("Suspending first run of use_server_future");
  94. cx.suspend();
  95. }
  96. None
  97. } else {
  98. Some(state)
  99. }
  100. }
  101. pub struct UseServerFuture<T> {
  102. update: Arc<dyn Fn()>,
  103. needs_regen: Cell<bool>,
  104. task: Cell<Option<TaskId>>,
  105. dependencies: Vec<Box<dyn Any>>,
  106. value: Rc<RefCell<Option<Box<T>>>>,
  107. }
  108. impl<T> UseServerFuture<T> {
  109. /// Restart the future with new dependencies.
  110. ///
  111. /// Will not cancel the previous future, but will ignore any values that it
  112. /// generates.
  113. pub fn restart(&self) {
  114. self.needs_regen.set(true);
  115. (self.update)();
  116. }
  117. /// Forcefully cancel a future
  118. pub fn cancel(&self, cx: &ScopeState) {
  119. if let Some(task) = self.task.take() {
  120. cx.remove_future(task);
  121. }
  122. }
  123. /// Return any value, even old values if the future has not yet resolved.
  124. ///
  125. /// If the future has never completed, the returned value will be `None`.
  126. pub fn value(&self) -> Ref<'_, T> {
  127. Ref::map(self.value.borrow(), |v| v.as_deref().unwrap())
  128. }
  129. /// Get the ID of the future in Dioxus' internal scheduler
  130. pub fn task(&self) -> Option<TaskId> {
  131. self.task.get()
  132. }
  133. /// Get the current state of the future.
  134. pub fn reloading(&self) -> bool {
  135. self.task.get().is_some()
  136. }
  137. }