suspense.rs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. use dioxus::core::ElementId;
  2. use dioxus::core::{Mutation::*, SuspenseBoundary};
  3. use dioxus::prelude::*;
  4. use dioxus_core::SuspenseContext;
  5. use std::future::IntoFuture;
  6. use std::{rc::Rc, time::Duration};
  7. #[tokio::test]
  8. async fn it_works() {
  9. let mut dom = VirtualDom::new(app);
  10. let mutations = dom.rebuild().santize();
  11. // We should at least get the top-level template in before pausing for the children
  12. assert_eq!(
  13. mutations.template_mutations,
  14. [
  15. CreateElement { name: "div" },
  16. CreateStaticText { value: "Waiting for child..." },
  17. CreateStaticPlaceholder,
  18. AppendChildren { m: 2 },
  19. SaveTemplate { name: "template", m: 1 }
  20. ]
  21. );
  22. // And we should load it in and assign the placeholder properly
  23. assert_eq!(
  24. mutations.edits,
  25. [
  26. LoadTemplate { name: "template", index: 0, id: ElementId(1) },
  27. // hmmmmmmmmm.... with suspense how do we guarantee that IDs increase linearly?
  28. // can we even?
  29. AssignId { path: &[1], id: ElementId(3) },
  30. AppendChildren { m: 1 },
  31. ]
  32. );
  33. // wait just a moment, not enough time for the boundary to resolve
  34. dom.wait_for_work().await;
  35. }
  36. fn app(cx: Scope) -> Element {
  37. cx.render(rsx!(
  38. div {
  39. "Waiting for child..."
  40. suspense_boundary {}
  41. }
  42. ))
  43. }
  44. fn suspense_boundary(cx: Scope) -> Element {
  45. cx.use_hook(|| cx.provide_context(Rc::new(SuspenseBoundary::new(cx.scope_id()))));
  46. // Ensure the right types are found
  47. cx.has_context::<SuspenseContext>().unwrap();
  48. cx.render(rsx!(async_child {}))
  49. }
  50. async fn async_child(cx: Scope<'_>) -> Element {
  51. use_future!(cx, || tokio::time::sleep(Duration::from_millis(10))).await;
  52. cx.render(rsx!(async_text {}))
  53. }
  54. async fn async_text(cx: Scope<'_>) -> Element {
  55. let username = use_future!(cx, || async {
  56. tokio::time::sleep(std::time::Duration::from_secs(1)).await;
  57. "async child 1"
  58. });
  59. let age = use_future!(cx, || async {
  60. tokio::time::sleep(std::time::Duration::from_secs(2)).await;
  61. println!("long future completed");
  62. 1234
  63. });
  64. let (_user, _age) = use_future!(cx, || async {
  65. tokio::join!(
  66. tokio::time::sleep(std::time::Duration::from_secs(1)),
  67. tokio::time::sleep(std::time::Duration::from_secs(2))
  68. );
  69. ("async child 1", 1234)
  70. })
  71. .await;
  72. let (username, age) = tokio::join!(username.into_future(), age.into_future());
  73. cx.render(rsx!( div { "Hello! {username}, you are {age}, {_user} {_age}" } ))
  74. }