useeffect.rs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. use dioxus_core::{ScopeState, TaskId};
  2. use std::{any::Any, cell::Cell, future::Future};
  3. use crate::UseFutureDep;
  4. /// A hook that provides a future that executes after the hooks have been applied
  5. ///
  6. /// Whenever the hooks dependencies change, the future will be re-evaluated.
  7. /// If a future is pending when the dependencies change, the previous future
  8. /// will be allowed to continue
  9. ///
  10. /// - dependencies: a tuple of references to values that are `PartialEq` + `Clone`
  11. ///
  12. /// ## Examples
  13. ///
  14. /// ```rust, no_run
  15. /// #[inline_props]
  16. /// fn Profile(cx: Scope, id: usize) -> Element {
  17. /// let name = use_state(cx, || None);
  18. ///
  19. /// // Only fetch the user data when the id changes.
  20. /// use_effect(cx, (id,), |(id,)| {
  21. /// to_owned![name];
  22. /// async move {
  23. /// let user = fetch_user(id).await;
  24. /// name.set(user.name);
  25. /// }
  26. /// });
  27. ///
  28. /// let name = name.get().clone().unwrap_or("Loading...".to_string());
  29. ///
  30. /// render!(
  31. /// p { "{name}" }
  32. /// )
  33. /// }
  34. ///
  35. /// fn app(cx: Scope) -> Element {
  36. /// render!(Profile { id: 0 })
  37. /// }
  38. /// ```
  39. pub fn use_effect<T, F, D>(cx: &ScopeState, dependencies: D, future: impl FnOnce(D::Out) -> F)
  40. where
  41. T: 'static,
  42. F: Future<Output = T> + 'static,
  43. D: UseFutureDep,
  44. {
  45. struct UseEffect {
  46. needs_regen: bool,
  47. task: Cell<Option<TaskId>>,
  48. dependencies: Vec<Box<dyn Any>>,
  49. }
  50. let state = cx.use_hook(move || UseEffect {
  51. needs_regen: true,
  52. task: Cell::new(None),
  53. dependencies: Vec::new(),
  54. });
  55. if dependencies.clone().apply(&mut state.dependencies) || state.needs_regen {
  56. // We don't need regen anymore
  57. state.needs_regen = false;
  58. // Create the new future
  59. let fut = future(dependencies.out());
  60. state.task.set(Some(cx.push_future(async move {
  61. fut.await;
  62. })));
  63. }
  64. }
  65. #[cfg(test)]
  66. mod tests {
  67. use super::*;
  68. #[allow(unused)]
  69. #[test]
  70. fn test_use_future() {
  71. use dioxus_core::prelude::*;
  72. struct MyProps {
  73. a: String,
  74. b: i32,
  75. c: i32,
  76. d: i32,
  77. e: i32,
  78. }
  79. fn app(cx: Scope<MyProps>) -> Element {
  80. // should only ever run once
  81. use_effect(cx, (), |_| async move {
  82. //
  83. });
  84. // runs when a is changed
  85. use_effect(cx, (&cx.props.a,), |(a,)| async move {
  86. //
  87. });
  88. // runs when a or b is changed
  89. use_effect(cx, (&cx.props.a, &cx.props.b), |(a, b)| async move {
  90. //
  91. });
  92. todo!()
  93. }
  94. }
  95. }