suspense.rs 2.7 KB

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