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::rc::Rc;
  6. use std::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(|| {
  47. cx.provide_context(Rc::new(SuspenseContext::new(cx.scope_id())));
  48. });
  49. // Ensure the right types are found
  50. cx.has_context::<Rc<SuspenseContext>>().unwrap();
  51. cx.render(rsx!(async_child {}))
  52. }
  53. async fn async_child(cx: Scope<'_>) -> Element {
  54. use_future!(cx, || tokio::time::sleep(Duration::from_millis(10))).await;
  55. cx.render(rsx!(async_text {}))
  56. }
  57. async fn async_text(cx: Scope<'_>) -> Element {
  58. let username = use_future!(cx, || async {
  59. tokio::time::sleep(std::time::Duration::from_secs(1)).await;
  60. "async child 1"
  61. });
  62. let age = use_future!(cx, || async {
  63. tokio::time::sleep(std::time::Duration::from_secs(2)).await;
  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. }