Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suspense boundaries/pure HTML out of order streaming/anyhow like error handling #2365

Open
wants to merge 109 commits into
base: main
Choose a base branch
from

Conversation

ealmloff
Copy link
Member

@ealmloff ealmloff commented Apr 24, 2024

This PR improves context based suspense by bubbling suspense to the nearest suspense boundary.

This allows you to handle suspense at a single boundary which makes it easier to show an unified loading UI.

It uses the current extension trait to return early when a suspended resource is encountered, but this now returns an error instead of None to avoid issues when the suspense is handled manually in the component.

// Suspense context
#[component]
fn Parent() -> Element {
    rsx! {
        ErrorBoundary {
            handle_error: |err| rsx! { div { {err} } },
            Suspense {
                pending: |suspense| rsx! { div { {suspense} } },
                Doggo {}
            }
        }
    }
}

#[component]
fn Doggo() -> Element {
    let download_progress = use_signal(|| 0.);
    let mut fut = use_resource(move || async move { download_model(download_progress).await })
        .suspend()
        // You can optionally add a hint for the suspense boundary to render
        .with_suspense_placeholder(move || rsx!("Downloading LLM... {download_progress}% done))?
        .throw()
        // You can optionally add a hint for the error boundary to render
        .show_with(|err| rsx!("hugging face is down 🙁: {err:?}"))?;

    todo!()
}

Breaking changes:

  • This PR changes the Element type from Option to Result to make it easier to return errors early, and properly track the result of the component. Without this change, if you throw or suspend, handle it manually and then return None manually, dioxus will try to handle the suspense/error for you

Closes #1335
Closes #2389
Closes #2264

Stacked on top of #2226, #2437, #2444

@ealmloff ealmloff added enhancement New feature or request core relating to the core implementation of the virtualdom breaking This is a breaking change fullstack related to the fullstack crate labels Apr 24, 2024
@ealmloff
Copy link
Member Author

ealmloff commented Jun 6, 2024

Still some paper cuts here, but the initial version of suspense boundaries and component errors is working. Here are a few things I would like to improve in future PRs:

  1. Server function errors don't automatically convert into CapturedError - Switching to a custom error type in server functions can fix this
  2. Out of order streaming can cause large html streams if the page is large and updates are frequent - In the future we should try to patch just suspense boundaries if that is the only part of the UI that was updated

@ealmloff ealmloff marked this pull request as ready for review June 6, 2024 18:09
@ealmloff ealmloff marked this pull request as draft June 6, 2024 19:37
@ealmloff ealmloff marked this pull request as draft June 6, 2024 19:37
@ealmloff ealmloff marked this pull request as draft June 6, 2024 19:37
@ealmloff ealmloff marked this pull request as ready for review June 6, 2024 20:38
@ealmloff
Copy link
Member Author

ealmloff commented Jun 7, 2024

mounted events are working correctly, but effects currently run inside of suspended nodes instead of waiting for suspense to finish before running

@ealmloff ealmloff marked this pull request as draft June 7, 2024 02:20
@ealmloff ealmloff marked this pull request as ready for review June 10, 2024 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking This is a breaking change core relating to the core implementation of the virtualdom enhancement New feature or request fullstack related to the fullstack crate
Projects
None yet
1 participant