Fix router state after client side navigation (#4383)

* Fix router state after client side navigation

* add client side navigation to the fullstack routing spec

* fix playwright test
This commit is contained in:
Evan Almloff authored and GitHub committed 2025-07-07 13:43:32 -05:00
1 parent ddc94cf44c
commit b252528722
4 files changed
+53 -5

No files matched your search

+3 -5
View File
@@ -2,10 +2,8 @@
use std::cell::OnceCell;
use dioxus_core::{
prelude::{generation, queue_effect},
schedule_update,
};
use dioxus_core::{prelude::queue_effect, schedule_update};
use dioxus_fullstack_protocol::is_hydrating;
use dioxus_history::History;
// If we are currently in a scope and this is the first run then queue a rerender
@@ -14,7 +12,7 @@ fn match_hydration<O>(
during_hydration: impl FnOnce() -> O,
after_hydration: impl FnOnce() -> O,
) -> O {
if generation() == 0 {
if is_hydrating() {
let update = schedule_update();
queue_effect(move || update());
during_hydration()
+13
View File
@@ -144,6 +144,19 @@ impl<T> SerializeContextEntry<T> {
}
}
/// Check if the client is currently rendering a component for hydration. Always returns true on the server.
pub fn is_hydrating() -> bool {
#[cfg(feature = "web")]
{
// On the client, we can check if the context is set
CONTEXT.with(|context| context.borrow().is_some())
}
#[cfg(not(feature = "web"))]
{
true
}
}
/// Get or insert the current serialize context. On the client, the hydration context this returns
/// will always return `TakeDataError::DataNotAvailable` if hydration of the current chunk is finished.
pub fn serialize_context() -> HydrationContext {
@@ -51,3 +51,33 @@ test("unknown route", async ({ request }) => {
expect(response.status()).toBe(404);
});
// Clicking the link on the home page should navigate to the blog route
test("click blog link", async ({ page }) => {
await page.goto("http://localhost:8888");
// Click the link to the blog route
await page.locator('a').click();
// Wait for navigation to complete
await page.waitForURL("http://localhost:8888/blog/1/");
// Check that the blog page is displayed
const text = await page.textContent("body");
expect(text).toContain("id: 1");
});
// Clicking the link on the blog page should navigate back to the home route
test("click home link from blog", async ({ page }) => {
await page.goto("http://localhost:8888/blog/1");
// Click the link to the home route
await page.locator('a').click();
// Wait for navigation to complete
await page.waitForURL("http://localhost:8888");
// Check that the home page is displayed
const text = await page.textContent("body");
expect(text).toContain("Home");
});
@@ -36,6 +36,9 @@ enum Route {
#[component]
fn Blog(id: i32) -> Element {
let route: Route = use_route();
assert_eq!(route, Route::Blog { id });
rsx! {
Link { to: Route::Home {}, "Go home" }
"id: {id}"
@@ -51,8 +54,12 @@ fn ThrowsError() -> Element {
#[component]
fn Home() -> Element {
let route: Route = use_route();
assert_eq!(route, Route::Home);
rsx! {
"Home"
Link { to: Route::Blog { id: 1 }, "Go to blog 1" }
}
}