
Every AI coding assistant was trained on React 18 patterns. When you're building with React 19 +...
Every AI coding assistant was trained on React 18 patterns. When you're building with React 19 + Next.js 15, the AI generates code that compiles perfectly but fails at runtime or behaves unexpectedly.
Here are the 4 most common React 19 traps I've documented, with .mdc rules to prevent each one.
{ pending: false } foreverThe trap: The AI places useFormStatus() in the same component that renders the <form>. This will NEVER work — useFormStatus only reads status from a parent <form>.
// ❌ AI generates this — pending is ALWAYS false
'use client'
export function MyForm() {
const { pending } = useFormStatus()
return (
<form action={createItem}>
<Button disabled={pending}>Submit</Button>
</form>
)
}
// ✅ Extract the button to a child component
function SubmitButton() {
const { pending } = useFormStatus()
return <Button disabled={pending}>{pending ? 'Saving...' : 'Submit'}</Button>
}
export function MyForm() {
return (
<form action={createItem}>
<SubmitButton />
</form>
)
}
React 19 renamed useFormState to useActionState and moved it from react-dom to react. The AI generates the old import because its training data is 99% React 18.
// ❌ Deprecated — AI generates this
import { useFormState } from 'react-dom'
// ✅ React 19
import { useActionState } from 'react'
const [state, formAction, isPending] = useActionState(serverAction, initialState)
In React 19, ref is a regular prop. The AI wraps every component in forwardRef() because that's what it learned from thousands of React 18 examples.
// ❌ Unnecessary boilerplate in React 19
const MyInput = forwardRef<HTMLInputElement, Props>((props, ref) => {
return <input ref={ref} {...props} />
})
// ✅ React 19 — ref is a regular prop
function MyInput({ ref, ...props }: Props & { ref?: React.Ref<HTMLInputElement> }) {
return <input ref={ref} {...props} />
}
This is the #1 runtime crash. In Next.js 15, params and searchParams are Promise objects. The AI generates synchronous destructuring because Next.js 14 used synchronous params.
// ❌ Compiles in dev, crashes in production
export default function Page({ params }: { params: { id: string } }) {
const { id } = params
}
// ✅ Next.js 15 — params are async
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params
}
Each of these traps has a corresponding .mdc rule file that activates based on file globs. When the AI opens a .tsx file, the rules inject the correct patterns into the context window, overriding the stale training data.
I've documented 29 of these patterns (React 19, Next.js 15, Supabase SSR, Stripe) as open source .mdc rule files:
GitHub: github.com/vibestackdev/vibe-stack
Quick install (5 free rules):
npx vibe-stack-rules init
What React 19 traps have you hit with AI code generation? I'd love to add them to the rule set.
cursorCursor Automations in 2026: wire event-triggered coding agents to Slack, CI, and...
aiThe specs exist. The AI just can't see them. I've always been the type who builds hobby...
amazonbedrockConnect Claude Code, Cursor and Codex to Amazon Bedrock's new console (2026) Summary. On 5...
aiThere is a weird uncanny valley with LLM-generated UI right now. The code functions perfectly, but if...
aiI went down a rabbit hole this morning reading the late-2025 Juejin AI roundups side by side, and the...
mcpInstall guide and config at curatedmcp.com Zendesk MCP: Let Claude Handle Your Support...
Workflows from the Neura Market marketplace related to this Cursor resource