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

use_server_future Hydration error #3041

Open
3 tasks
hackartists opened this issue Oct 8, 2024 · 3 comments
Open
3 tasks

use_server_future Hydration error #3041

hackartists opened this issue Oct 8, 2024 · 3 comments
Labels
fullstack related to the fullstack crate needs reproduction An issue that is missing a reproduction

Comments

@hackartists
Copy link
Contributor

hackartists commented Oct 8, 2024

Problem

  • main.rs
    #[cfg(feature = "web")]
    dioxus_web::launch::launch(App, vec![], dioxus_web::Config::new().hydrate(true));

    #[cfg(feature = "server")]
    dioxus::launch(App);
  • component.rs
    • use_resource works properly.
    • use_server_future causes hydration error.
#[component]
pub fn CollectionListPage(lang: Language) -> Element {
    let navigator = use_navigator();
    let mut collections: Signal<Vec<Collection>> = Signal::default();
    let mut num_items: Signal<usize> = Signal::default();

    let collections = use_resource(move || async move {
        match list_collections(None, None, Some(0), Some(100)).await {
            Ok(v) => v,
            Err(e) => {
                tracing::error!("failed to fetch collections: {:?}", e);
                vec![]
            }
        }
    })
    .value();

    // FIXME: it needs to be rendered by the server for SSR.
    // let collections = use_server_future(move || async move {
    //     match list_collections(None, None, Some(0), Some(100)).await {
    //         Ok(v) => v,
    //         Err(e) => {
    //             tracing::error!("failed to fetch collections: {:?}", e);
    //             vec![]
    //         }
    //     }
    // })?
    // .value();

    rsx! {
        div {
            class: "w-full h-full",
            GridLayout {
                class: "py-4 lg:py-10",
                if let Some(collections) = collections() {
                    for collection in collections {
                        ImageCard {
                            onclick: move |_evt| {
                                navigator
                                    .push(Route::CollectionDetailPage {
                                        lang: lang.clone(),
                                        agit_id: collection.agit_id.unwrap_or_default(),
                                        collection_id: collection.id,
                                    });
                            },
                            image_url: collection.logo.clone(),
                            p { class: "font-semibold text-2xl pt-4 line-clamp-1", {collection.name.clone()} }
                            p { class: "text-[#666666] font-medium",
                                "Item "
                                span { class: "text-primary ml-1", "{num_items()}" }
                            }
                        }
                    }
                }
            }
        }
    }
}

Steps To Reproduce

Steps to reproduce the behavior:

Expected behavior

  • Render without errors
  • It can navigate to other pages.

Screenshots

image

Environment:

  • Dioxus version: 0.6.0-alpha.2
  • Rust version: rustc 1.80.1 (3f5fd8dd4 2024-08-06)
  • OS info: Arch linux 6.11.2
  • App platform: fullstack

Questionnaire

  • I'm interested in fixing this myself but don't know where to start
  • I would like to fix and I have a solution
  • I don't have time to fix this right now, but maybe later
@ealmloff
Copy link
Member

ealmloff commented Oct 8, 2024

#[cfg(feature = "web")]
dioxus_web::launch::launch(App, vec![], dioxus_web::Config::new().hydrate(true));

#[cfg(feature = "server")]
dioxus::launch(App);

If you are using fullstack, you need to launch fullstack on the web renderer. The fullstack entry point has special logic for hydrating server functions:

LaunchBuilder::new()
    .with_cfg(web!{dioxus_web::Config::new().hydrate(true)})
    .launch(App)

@hackartists
Copy link
Contributor Author

hackartists commented Oct 9, 2024

#[cfg(feature = "web")]
dioxus_web::launch::launch(App, vec![], dioxus_web::Config::new().hydrate(true));

#[cfg(feature = "server")]
dioxus::launch(App);

If you are using fullstack, you need to launch fullstack on the web renderer. The fullstack entry point has special logic for hydrating server functions:

LaunchBuilder::new()
    .with_cfg(web!{dioxus_web::Config::new().hydrate(true)})
    .launch(App)

I've changed main.rs as below

    #[cfg(feature = "web")]
    dioxus::prelude::LaunchBuilder::new()
        .with_cfg(web! {dioxus_web::Config::new().hydrate(true)})
        .launch(App);

    #[cfg(feature = "server")]
    dioxus_aws::launch(App);

However, if uncomment use_server_future, it causes same error when refresh on that page. @ealmloff

As a additional information, the above use_server_future code does work for 0.5 version of dioxus.

@ealmloff ealmloff added fullstack related to the fullstack crate needs reproduction An issue that is missing a reproduction labels Oct 9, 2024
@ealmloff
Copy link
Member

ealmloff commented Oct 9, 2024

Could you provide a minimal reproduction for this issue? I cannot reproduce it with a simple router example with a server future:

use dioxus::prelude::*;

fn main() {
    LaunchBuilder::fullstack()
        .with_cfg(server_only!(ServeConfig::builder().incremental(
            IncrementalRendererConfig::default()
                .invalidate_after(std::time::Duration::from_secs(120)),
        )))
        .launch(app);
}

fn app() -> Element {
    rsx! { Router::<Route> {} }
}

#[derive(Clone, Routable, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
enum Route {
    #[route("/")]
    Home {},

    #[route("/blog/:id/")]
    Blog { id: i32 },
}

#[component]
fn Blog(id: i32) -> Element {
    let future = use_server_future(get_server_data)?;
    let future = future.value();

    rsx! {
        "{future:?}"
        Link { to: Route::Home {}, "Go to counter" }
        table {
            tbody {
                for _ in 0..id {
                    tr {
                        for _ in 0..id {
                            td { "hello world!" }
                        }
                    }
                }
            }
        }
    }
}

#[component]
fn Home() -> Element {
    let mut count = use_signal(|| 0);
    let mut text = use_signal(|| "...".to_string());

    rsx! {
        Link { to: Route::Blog { id: count() }, "Go to blog" }
        div {
            h1 { "High-Five counter: {count}" }
            button { onclick: move |_| count += 1, "Up high!" }
            button { onclick: move |_| count -= 1, "Down low!" }
            button {
                onclick: move |_| async move {
                    if let Ok(data) = get_server_data().await {
                        println!("Client received: {}", data);
                        text.set(data.clone());
                        post_server_data(data).await.unwrap();
                    }
                },
                "Run server function!"
            }
            "Server said: {text}"
        }
    }
}

#[server(PostServerData)]
async fn post_server_data(data: String) -> Result<(), ServerFnError> {
    println!("Server received: {}", data);

    Ok(())
}

#[server(GetServerData)]
async fn get_server_data() -> Result<String, ServerFnError> {
    Ok("Hello from the server!".to_string())
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fullstack related to the fullstack crate needs reproduction An issue that is missing a reproduction
Projects
None yet
Development

No branches or pull requests

2 participants