From eec083c91aecb85a9d04e2d5d242461b8beea545 Mon Sep 17 00:00:00 2001 From: viettranx Date: Thu, 19 Mar 2026 22:39:41 +0700 Subject: [PATCH] docs: add ErrorBoundary key + route params rules to CLAUDE.md --- CLAUDE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 20703b63..1cd5a3a0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -111,3 +111,5 @@ When implementing or modifying web UI components, follow these rules to ensure m - **Landscape:** Use `landscape-compact` class on top bars to reduce padding in phone landscape orientation (`max-height: 500px`) - **Portal dropdowns in dialogs:** Custom dropdown components using `createPortal(content, document.body)` MUST add `pointer-events-auto` class to the dropdown element. Radix Dialog sets `pointer-events: none` on `document.body` — without this class, dropdowns are unclickable. Radix-native portals (Select, Popover) handle this automatically - **Timezone:** User timezone stored in Zustand (`useUiStore`). Charts use `formatBucketTz()` from `lib/format.ts` with native `Intl.DateTimeFormat` — no date-fns-tz dependency +- **ErrorBoundary key:** `AppLayout` uses `` which strips dynamic segments (`/chat/session-A` → `/chat`). NEVER use `key={location.pathname}` on ErrorBoundary/Suspense wrapping `` — it causes full page remount on param changes. Pages with sub-navigation (chat sessions, detail pages) must share a stable key +- **Route params as source of truth:** For pages with URL params (e.g. `/chat/:sessionKey`), derive state from `useParams()` — do NOT duplicate into `useState`. Dual state causes race conditions between `setState` and `navigate()` leading to UI flash (state bounces: B→A→B). Use optional params (`/chat/:sessionKey?`) instead of two separate routes