fix(pwa): stop calendar remount/flash on re-render (Bug B root cause)

The calendar flashed whenever the event popup/form closed or a post-write events
refetch landed. Root cause: CalendarContent was a function component DEFINED
INSIDE CalendarShell's render and used as <CalendarContent />. A nested component
has a new identity every render, so React unmounted+remounted its whole subtree
— including <ScheduleXCalendar> — on ANY CalendarShell re-render. The earlier
Bug B work only minimized re-renders (Zustand selectors) to dodge this; the
resync-before-done fix made the post-write ['events'] refetch deliver changed
data again, so the remount/flash returned.

Fix: render the content as a plain JSX element value (const calendarContent)
referenced at both layout sites instead of a nested component type. Element
values reconcile in place across re-renders — no remount, no flash.
This commit is contained in:
Lucas Berger
2026-06-07 17:55:56 -04:00
parent ae9fd9d790
commit 2e10752a59
+11 -6
View File
@@ -236,9 +236,15 @@ export function CalendarShell() {
// ── Calendar content ─────────────────────────────────────────────────────── // ── Calendar content ───────────────────────────────────────────────────────
// The content panel (right of sidebar on desktop, full-width on phone) // The content panel (right of sidebar on desktop, full-width on phone).
function CalendarContent() { //
return ( // This is a plain JSX value, NOT a nested `function CalendarContent()` rendered
// as `<CalendarContent />`. A component defined inside render has a new identity
// every render, so React unmounts+remounts its entire subtree — including
// <ScheduleXCalendar> — on ANY CalendarShell re-render (popup/form close, post-
// write events refetch). That full remount is the "calendar flash" (Bug B). As
// an element value it reconciles in place across re-renders: no remount, no flash.
const calendarContent = (
<div <div
style={{ style={{
flex: 1, flex: 1,
@@ -331,7 +337,6 @@ export function CalendarShell() {
)} )}
</div> </div>
) )
}
// ── Full layout ──────────────────────────────────────────────────────────── // ── Full layout ────────────────────────────────────────────────────────────
@@ -355,7 +360,7 @@ export function CalendarShell() {
currentUserName={meQuery.data?.user.displayName ?? undefined} currentUserName={meQuery.data?.user.displayName ?? undefined}
/> />
<InstallPrompt /> <InstallPrompt />
<CalendarContent /> {calendarContent}
<EventDetailPopover /> <EventDetailPopover />
{/* New Event FAB — phone: bottom-right floating action button (UI-SPEC §Interaction Contract) */} {/* New Event FAB — phone: bottom-right floating action button (UI-SPEC §Interaction Contract) */}
@@ -457,7 +462,7 @@ export function CalendarShell() {
</button> </button>
</div> </div>
<CalendarContent /> {calendarContent}
</div> </div>
{/* EventDetailPopover — standalone mode driven by Zustand openEventId */} {/* EventDetailPopover — standalone mode driven by Zustand openEventId */}