suspense.rs 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. use dioxus::core::ElementId;
  2. use dioxus::core::{Mutation::*, SuspenseContext};
  3. use dioxus::prelude::*;
  4. use std::future::IntoFuture;
  5. use std::time::Duration;
  6. #[tokio::test]
  7. async fn it_works() {
  8. let mut dom = VirtualDom::new(app);
  9. let mutations = dom.rebuild().santize();
  10. // We should at least get the top-level template in before pausing for the children
  11. // note: we dont test template edits anymore
  12. // assert_eq!(
  13. // mutations.templates,
  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, id: ElementId(0) },
  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(|| {
  46. cx.provide_context(SuspenseContext::new(cx.scope_id()));
  47. });
  48. // Ensure the right types are found
  49. cx.has_context::<SuspenseContext>().unwrap();
  50. cx.render(rsx!(async_child {}))
  51. }
  52. async fn async_child(cx: Scope<'_>) -> Element {
  53. use_future!(cx, || tokio::time::sleep(Duration::from_millis(10))).await;
  54. cx.render(rsx!(async_text {}))
  55. }
  56. async fn async_text(cx: Scope<'_>) -> Element {
  57. let username = use_future!(cx, || async {
  58. tokio::time::sleep(std::time::Duration::from_secs(1)).await;
  59. "async child 1"
  60. });
  61. let age = use_future!(cx, || async {
  62. tokio::time::sleep(std::time::Duration::from_secs(2)).await;
  63. println!("long future completed");
  64. 1234
  65. });
  66. let (_user, _age) = use_future!(cx, || async {
  67. tokio::join!(
  68. tokio::time::sleep(std::time::Duration::from_secs(1)),
  69. tokio::time::sleep(std::time::Duration::from_secs(2))
  70. );
  71. ("async child 1", 1234)
  72. })
  73. .await;
  74. let (username, age) = tokio::join!(username.into_future(), age.into_future());
  75. cx.render(rsx!( div { "Hello! {username}, you are {age}, {_user} {_age}" } ))
  76. }