Repository navigation
Fix Blazor WASM page is instantiated twice when navigating between pages with different layouts issue - #70018
Conversation
…ages with different layouts` issue
|
Thanks for your PR, @BharatRamsf3693. Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
There was a problem hiding this comment.
🔵 Needs a closer look
The lifecycle-sensitive fix needs human review and confirmation that the unit and browser regressions fail without the fix and pass with it.
No open issues 🎉
What changed in this PR
This PR addresses #68004 by capturing route data for each RouteView render, preventing an outgoing layout from rendering the destination page with newer navigation data.
Changes:
- Bind page-rendering fragments to the route data captured when their layout is rendered.
- Add unit coverage for page instantiation, route parameters, and outgoing-page disposal.
- Add a browser regression scenario with different layouts and lifecycle tracing.
| File | Description |
|---|---|
| src/Components/test/testassets/BasicTestApp/RouteViewLayoutTransition/TrackedPageBase.cs | Records page construction and lifecycle events. |
| src/Components/test/testassets/BasicTestApp/RouteViewLayoutTransition/RouteViewLayoutTransitionApp.razor | Hosts the router and layout-transition scenario. |
| src/Components/test/testassets/BasicTestApp/RouteViewLayoutTransition/RootLayout.razor | Provides navigation links and lifecycle output. |
| src/Components/test/testassets/BasicTestApp/RouteViewLayoutTransition/NestedLayout.razor | Adds the nested layout used by the initial page. |
| src/Components/test/testassets/BasicTestApp/RouteViewLayoutTransition/DefaultLayoutPage.razor | Supplies the initial page and route parameter display. |
| src/Components/test/testassets/BasicTestApp/RouteViewLayoutTransition/ComponentLifecycleTrace.cs | Stores lifecycle entries and notifies subscribers. |
| src/Components/test/testassets/BasicTestApp/RouteViewLayoutTransition/ComponentLifecycleLog.razor | Displays lifecycle entries in the browser. |
| src/Components/test/testassets/BasicTestApp/RouteViewLayoutTransition/CascadingStateProvider.razor | Supplies cascading state for the regression scenario. |
| src/Components/test/testassets/BasicTestApp/RouteViewLayoutTransition/AlternateLayoutPage.razor | Supplies the destination page with a different layout. |
| src/Components/test/testassets/BasicTestApp/Index.razor | Registers the new test scenario. |
| src/Components/test/E2ETest/Tests/RoutingTest.cs | Checks destination-page construction count during browser navigation. |
| src/Components/Components/test/RouteViewTest.cs | Adds renderer-level layout-transition regression coverage. |
| src/Components/Components/src/RouteView.cs | Captures route data in the page-rendering fragment. |
Review effort: Balanced
|
/review |
PureWeen
left a comment
There was a problem hiding this comment.
Two issues need attention at this commit.
Human-directed and GitHub Copilot-generated.
| builder.OpenComponent<LayoutView>(0); | ||
| builder.AddComponentParameter(1, nameof(LayoutView.Layout), pageLayoutType); | ||
| builder.AddComponentParameter(2, nameof(LayoutView.ChildContent), (RenderFragment)RenderPageWithParameters); | ||
| builder.AddComponentParameter(2, nameof(LayoutView.ChildContent), (RenderFragment)(contentBuilder => RenderPageWithParameters(contentBuilder, routeData))); |
There was a problem hiding this comment.
Capturing routeData here fixes the different-layout case, but it also lets a superseded fragment replay stale parameters into a retained page. With the same page/layout under a changing non-fixed cascade, the retained layout is queued before RouteView, so this old closure runs first. For reference-valued route parameters, conservative parameter comparison calls SetParametersAsync with the old model and then the new one, allowing stale OnParametersSet{Async} work to race the destination update. Please suppress or version superseded fragments while preserving the different-layout fix, and add a same-page/same-layout reference-parameter regression.
| Browser.Equal("second", () => app.FindElement(By.Id("page-value")).Text); | ||
| var trace = app.FindElement(By.Id("instantiation-log")).Text; | ||
|
|
||
| Assert.Equal(1, trace.Split('\n').Count(line => line.Contains($"{nameof(AlternateLayoutPage)}[") && line.Contains("constructor"))); |
There was a problem hiding this comment.
This assertion reads a process-static trace that is never cleared. In the inherited ServerRoutingTest, assembly-level retry reruns the test against the same in-process server fixture; navigating through about:blank resets the browser/circuit, not InstantiationTrace. If an attempt constructs AlternateLayoutPage and then fails transiently, the retry adds another constructor entry and this exactly-one assertion deterministically fails again. Please make the trace attempt- or mount-scoped, or reset it safely before asserting the count.
Fix
Blazor WASM page is instantiated twice when navigating between pages with different layoutsissueSummary of the changes
Prevent duplicate page instantiation during layout transitions
Description
Fixes a Blazor RouteView issue where navigating between pages that use different layouts could instantiate the destination page twice.
Changes made
Fixes #68004