From cb5c2fd2b9fd7faca02b52a65ca5a0b0070789fb Mon Sep 17 00:00:00 2001 From: Daniel Harvey Date: Thu, 21 May 2026 06:22:55 -0400 Subject: [PATCH] fix(public): move DeepDrftMenu dark-mode sync to OnAfterRenderAsync to unhang SSR prerender under interactive Routes --- .../Layout/DeepDrftMenu.razor | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/DeepDrftPublic.Client/Layout/DeepDrftMenu.razor b/DeepDrftPublic.Client/Layout/DeepDrftMenu.razor index 4c7ce0c..ad495c5 100644 --- a/DeepDrftPublic.Client/Layout/DeepDrftMenu.razor +++ b/DeepDrftPublic.Client/Layout/DeepDrftMenu.razor @@ -77,23 +77,21 @@ private bool _mobileMenuOpen; private Guid _viewportSubscriptionId; - protected override async Task OnInitializedAsync() - { - // During SSR prerender the dark-mode state is already seeded by the server-side - // DarkModeService (via IHttpContextAccessor + DarkModeSettings + PersistentComponentState). - // Invoking the EventCallback here during prerender triggers a re-render cycle on the - // SSR renderer that never completes, hanging the page. Guard to interactive-only so - // the cookie sync only runs when the component is actually mounted in the browser. - if (!RendererInfo.IsInteractive) return; - - IsDarkMode = DarkModeCookieService.GetDarkModeAsync(); - await IsDarkModeChanged.InvokeAsync(IsDarkMode); - } - protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { + // Dark-mode cookie sync runs here (not OnInitializedAsync) because + // OnAfterRenderAsync(firstRender) is guaranteed not to execute during any + // SSR prerender pass. During prerender (now interactive across all of Routes), + // awaiting IsDarkModeChanged.InvokeAsync triggers a parent re-render cycle + // that cannot complete on the prerender renderer and hangs the response. + // Server-side DarkModeService has already seeded DarkModeSettings via + // PersistentComponentState, so the prerender paint is already correct; + // this call just reconciles with the live cookie once on the client. + IsDarkMode = DarkModeCookieService.GetDarkModeAsync(); + await IsDarkModeChanged.InvokeAsync(IsDarkMode); + _viewportSubscriptionId = Guid.NewGuid(); await BrowserViewportService.SubscribeAsync( _viewportSubscriptionId,