suspense.rs 3.1 KB

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