From f5a521039a29062a8ee654c124420c8e1514e5dc Mon Sep 17 00:00:00 2001 From: dolphin Date: Thu, 13 Aug 2026 17:28:52 +0800 Subject: [PATCH] docs(client): document useLocalize unstable-reference pitfall Root cause of the channel edit page's unresponsive inputs/switches: useLocalize() returns a new function identity every render, which cascaded through a useCallback dep chain into a "hydrate form from server data" effect, causing it to re-fire (and reset the form) on every keystroke. --- src/frontend/client/AGENTS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/frontend/client/AGENTS.md b/src/frontend/client/AGENTS.md index a0e9c50fe..3eeda7f51 100644 --- a/src/frontend/client/AGENTS.md +++ b/src/frontend/client/AGENTS.md @@ -35,3 +35,6 @@ Vite 6 + React 18 + TypeScript + TailwindCSS 3 + Radix UI (shadcn/ui) + **Recoil - Typography (new code): semantic classes `text-caption/body-sm/body/h4…h1` (auto-remap ≤768px) — not raw `text-sm/base` (基础-字体规范.md). - Neutral colors (new code): semantic tokens `text-text-1…4` / `bg-fill-1…4` / `border-border-base|-deep` / `success|warning|danger` — never `text-gray-*` or hex (基础-色彩规范.md). - Hover/touch: plain `hover:` classes ONLY (`hoverOnlyWhenSupported` disables them on touch app-wide) — **never invent hover variant prefixes**; touch press via `coarse-pointer:active:`; hover/active shade stays within the base color's own ramp (no cross-palette graying). + +## Known Pitfalls +- **`useLocalize()` return value is unstable**: `~/hooks/useLocalize.ts` returns a new arrow-function identity on every render (no memoization). Any `useCallback`/`useMemo` that lists `localize` in its deps is therefore also unstable every render. Never let such a callback sit in a `useEffect` dep array that's meant to run only when real data changes (e.g. a "hydrate form from server response" effect) — the effect will silently re-fire on every render and can reset in-progress user input/toggles on every keystroke. Found in `ChannelSettings/useChannelSettingsForm.ts` (`initBusinessFromChannel` dep), symptom: edit-page inputs/switches appeared unresponsive because the fetched detail was re-applied after every keystroke. Guard "run once when data arrives" effects with a ref/id check instead of relying on function-reference deps, or drop the `localize`-derived function from the dep array with a lint-justified comment.