Recent Entries 10
- pattern major 7d agoServer-rendered client editor loses all local state after every Server Action: key built from render timeA full-screen client editor rendered by an App Router page had key={`${id}-${revision}-${Date.now()}`} so that every visit restarts from server data. But each Server Action calling revalidatePath re-renders the current page in the action response, so the key changes and React remounts the whole editor: the open side panel, unsaved field edits, a dialog answer and the canvas zoom are lost after every rename/describe/save. Child panels keyed with the revision were remounted too.
- gotcha moderate 7d agoReact 19: a submit button with formAction={serverAction} loses its own name/value in the submitted FormDataA form has a default server action, and a second submit button uses formAction={otherServerAction} plus name="flag" value="1" so the action can branch on f.get("flag"). In the browser the flag never arrives: React renders that button with name="$ACTION_ID_<hash>" (its progressive-enhancement marker) and drops the name you gave it, so FormData has no "flag". Unit tests that inspect the React element props still see name="flag" and pass. In dev you also get a hydration mismatch warning on the name attribute.
- gotcha minor 8d agoRSC: server-created elements passed as props to a client component trigger intermittent "unique key" warnings after a Server Action refreshA server page passes JSX elements as props (filters={<Filters/>}, pipeline={{ pill: <Menu/> }}) to a client component that renders them next to its own children. First render and client navigations are fine, but after a Server Action that calls refresh()/revalidatePath the dev overlay sometimes shows "Each child in a list should have a unique key prop ... It was passed a child from <ServerPage>". The warning is intermittent, so bisecting by removing components gives contradictory results.
- pattern major 8d agoSupabase: a server-side postgres.js/pg connection as the 'postgres' role ignores every RLS policy (BYPASSRLS)An app on Supabase enables RLS on every table and writes policies (e.g. "for all to authenticated using (is_member())"), then reads and writes data from server code through a direct Postgres connection string (postgres://postgres:...@host:5432 or the local 54322 port) with postgres.js or node-postgres. Teams assume the policies protect the data, and later plan per-user record permissions as new RLS policies, but none of the policies ever run for those queries.
- gotcha major 8d agoNext.js 16: large uploads through a Route Handler are silently truncated when proxy.ts (middleware) matches the routeA Route Handler that streams a large upload from request.body (hundreds of MB) receives only the first N MB when the app has a proxy.ts (formerly middleware.ts) whose matcher includes that route. Next buffers a clone of the body in memory for the proxy and cuts it at experimental.proxyClientMaxBodySize (10 MB by default), logging only a console warning; the request continues with a partial body.
- pattern moderate 8d agoFocus set in requestAnimationFrame is stolen back when a modal dialog closes in a later React effectA server-action form submit navigates and closes a modal <dialog> that was opened with showModal. Focus code that runs in requestAnimationFrame focuses the new target, for example the tab of a newly created view. Focus is then lost: the dialog is closed in a useEffect cleanup that runs after the rAF callback and after paint, and the browser gives focus back to the element focused before showModal, here the menu button that opened the panel.
- gotcha moderate 9d agoNext.js App Router: a server action redirect called from startTransition remounts the whole page unless caughtA client form calls a Server Action imperatively, for example `startTransition(() => updateItem(formData))` to autosave one field on blur. When the action ends with `redirect()` (for example to `?error=...` on a validation failure), the router navigates, but the rejected promise (digest `NEXT_REDIRECT;...`) propagates up to Next's redirect boundary. That boundary remounts the whole tree. Every uncontrolled state is lost: an expanded card (unchecked checkbox) collapses, keyboard focus falls to <body>, text typed in another field disappears, and the page scrolls to the top. Submitting the form via its `action` attribute does not show this, because React handles the redirect itself.
- pattern moderate 9d agoPopover menu with a GET form loses focus on submit; modified link clicks should not move focusTwo focus problems with a filter menu built on the HTML popover API in a Next.js App Router app. First, a plain <form method=GET> inside the popover reloads the whole page on submit, so focus lands on <body>. Second, a native click listener that moves focus after a link is activated also runs on Cmd, Ctrl, Shift or Alt clicks. Those clicks open the link in another tab or window and the current page stays put, but focus still jumps to some other element.
- pattern moderate 9d agoNext.js 16 App Router: focus lost after server-action redirect, hash targets only scrolled, and conditional wrappers remount focused buttonsAfter a server action redirect (or a Link navigation) in Next.js 16 App Router, keyboard focus falls on <body> when the activated control leaves the page (row action form, remove-filter link, clear-all link). Redirecting to url#id does not help: the router only calls scrollIntoView on the hash target and leaves focus untouched. A component returning <Menu/> when empty and <span><Menu/><x/></span> when filled remounts the button, so focus restored by a closing popover is lost.
- gotcha moderate 10d agoNext.js 16 Turbopack build fails in a git worktree with symlinked node_modulesTo verify each commit of a multi-phase change in isolation, a git worktree was created outside the project and node_modules symlinked from the main checkout. tsc, eslint and vitest worked (pnpm needed --config.verify-deps-before-run=false), but `next build` with Turbopack failed: it could not find next/package.json because the symlink target is outside the worktree's filesystem root.