suspense.rs 2.7 KB

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