This skill should be used when the user is building, modifying, or reviewing React components or applications. It provides React 19.x development patterns and APIs that should be preferred over legacy approaches. Covers Actions, useActionState, useFormStatus, useOptimistic, use() API, Form Actions, ref as prop, Context as provider, document metadata, Server Components, Server Actions, prerender(), Activity component, useEffectEvent, cacheSignal(), and Partial Pre-rendering.
From engineering-toolsnpx claudepluginhub dionridley/claude-plugins --plugin engineering-toolsThis skill uses the workspace's default tool permissions.
references/actions.mdreferences/improvements.mdreferences/rendering.mdreferences/server-components.mdreferences/use-api.mdSearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
This skill provides guidance on React 19.x features that may not be in LLM training data. Focus is on new APIs, patterns, and migration from older React patterns.
When generating or modifying React code, always prefer React 19 patterns over legacy equivalents:
forwardRef wrappers with ref as a regular prop<Context.Provider> with <Context> directlyuseActionState and form actionsuseOptimistic{show && <Component />}) with <Activity> when state preservation mattersuse() instead of useContext() when context is read conditionallyuseEffectEvent to prevent unnecessary effect re-runs from non-reactive valuesConsult the decision tree below to select the appropriate API. For detailed patterns, consult the relevant reference file.
| Hook | Purpose | Import |
|---|---|---|
useActionState | Form state + pending + error handling | react |
useFormStatus | Read parent form's pending state | react-dom |
useOptimistic | Optimistic UI updates | react |
use | Read promises/context conditionally | react |
| Hook | Purpose | Import |
|---|---|---|
useEffectEvent | Stable event handlers in effects | react |
| Component | Purpose |
|---|---|
<Activity> | Control visibility/priority of subtrees |
| API | Change | Import |
|---|---|---|
useDeferredValue | New optional initialValue parameter | react |
| Function | Purpose | Import |
|---|---|---|
requestFormReset | Programmatically reset a form after action | react-dom |
Handling form submission?
├── Need pending state in child component? → useFormStatus
├── Need optimistic updates? → useOptimistic
├── Need form state + error handling? → useActionState
└── Simple async action? → useTransition with async
Reading async data?
├── In render, with Suspense? → use(promise)
└── In effect/event handler? → Regular await
Reading context conditionally?
└── After early return? → use(Context) instead of useContext
Effect needs reactive value but shouldn't re-run?
└── → useEffectEvent
Conditional rendering with state preservation?
└── → <Activity mode="visible|hidden">
// OLD: Manual state management
function OldForm() {
const [isPending, setIsPending] = useState(false);
const [error, setError] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
setIsPending(true);
const result = await submitData(new FormData(e.target));
setIsPending(false);
if (result.error) setError(result.error);
};
return <form onSubmit={handleSubmit}>...</form>;
}
// NEW: Form Actions with useActionState
function NewForm() {
const [error, submitAction, isPending] = useActionState(
async (prevState, formData) => {
const result = await submitData(formData);
if (result.error) return result.error;
redirect('/success');
return null;
},
null
);
return (
<form action={submitAction}>
<input name="field" />
<button disabled={isPending}>Submit</button>
{error && <p>{error}</p>}
</form>
);
}
// OLD: Required forwardRef wrapper
const OldInput = forwardRef(function OldInput({ label }, ref) {
return <input ref={ref} aria-label={label} />;
});
// NEW: ref is just a prop
function NewInput({ label, ref }) {
return <input ref={ref} aria-label={label} />;
}
// Both used the same way
<NewInput ref={inputRef} label="Name" />
// OLD
<ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
// NEW
<ThemeContext value={theme}>
{children}
</ThemeContext>
// useContext cannot be called after early return
function Component({ show }) {
if (!show) return null;
// const theme = useContext(ThemeContext); // ERROR!
const theme = use(ThemeContext); // OK!
return <div style={{ color: theme.color }}>...</div>;
}
// OLD: Unmounts and loses state
{isVisible && <ExpensiveComponent />}
// NEW: Preserves state, defers updates when hidden
<Activity mode={isVisible ? 'visible' : 'hidden'}>
<ExpensiveComponent />
</Activity>
// Problem: theme change causes reconnect
function ChatRoom({ roomId, theme }) {
useEffect(() => {
const conn = connect(roomId);
conn.on('connected', () => showNotification(theme));
return () => conn.disconnect();
}, [roomId, theme]); // theme shouldn't trigger reconnect!
}
// Solution: useEffectEvent
function ChatRoom({ roomId, theme }) {
const onConnected = useEffectEvent(() => {
showNotification(theme); // Always reads latest theme
});
useEffect(() => {
const conn = connect(roomId);
conn.on('connected', onConnected);
return () => conn.disconnect();
}, [roomId]); // Only roomId triggers reconnect
}
(previousState, formData) - don't forget previousState[state, action, isPending] - order mattersuseFormState in React DOM<form>{ pending, data, method, action }startTransition or form actionsuse()// NEW: Cleanup function syntax
<input
ref={(node) => {
// Setup
node.focus();
return () => {
// Cleanup when ref changes or unmounts
};
}}
/>
// BREAKING: Implicit returns now fail TypeScript
<div ref={current => (instance = current)} /> // BAD
<div ref={current => { instance = current; }} /> // GOOD
Available codemods for automatic migration from React 18 patterns:
npx codemod react/19/replace-forward-ref # forwardRef → ref as prop
npx codemod react/19/replace-context-provider # Context.Provider → Context
For detailed documentation on specific topics: