React 19 new features and APIs. Covers Actions, useActionState, useFormStatus, useOptimistic, use() hook, Server Components, Server Actions, improved ref handling, document metadata, and new compiler. USE WHEN: user mentions "React 19", "useActionState", "useFormStatus", "useOptimistic", "use() hook", "Server Components", "Server Actions", "React Compiler", asks about "React 19 features", "Actions in React", "ref as prop" DO NOT USE FOR: React 18 and earlier - use `react` skill instead, forms in general - use `react-forms` or `react-hook-form` skills instead

GitHub
安装命令
npx skhub add claude-dev-suite/react-19
Markdown
SKILL.md

React 19

Overview of New Features

FeatureDescription
ActionsAsync functions in transitions for data mutations
useActionStateHandle action state with pending/error
useFormStatusAccess parent form status
useOptimisticOptimistic UI updates
use()Read resources in render (Promises, Context)
Server ComponentsComponents that render on server
Server ActionsServer functions called from client
React CompilerAutomatic memoization
Ref as propPass ref directly without forwardRef

Actions

Actions are async functions used in transitions to handle mutations:

import { useTransition } from 'react';

function UpdateProfile() {
  const [isPending, startTransition] = useTransition();

  async function handleSubmit(formData: FormData) {
    startTransition(async () => {
      const result = await updateProfile(formData);
      if (result.error) {
        showToast(result.error);
      }
    });
  }

  return (
    <form action={handleSubmit}>
      <input name="name" type="text" />
      <button type="submit" disabled={isPending}>
        {isPending ? 'Saving...' : 'Save'}
      </button>
    </form>
  );
}

useActionState

Replaces the experimental useFormState. Manages form action state including pending status:

import { useActionState } from 'react';

interface FormState {
  message: string | null;
  errors: Record<string, string[]>;
}

async function createPost(prevState: FormState, formData: FormData): Promise<FormState> {
  const title = formData.get('title') as string;

  if (!title || title.length < 3) {
    return { message: null, errors: { title: ['Title must be at least 3 characters'] } };
  }

  try {
    await savePost({ title });
    return { message: 'Post created!', errors: {} };
  } catch (error) {
    return { message: 'Failed to create post', errors: {} };
  }
}

function CreatePostForm() {
  const [state, formAction, isPending] = useActionState(createPost, {
    message: null,
    errors: {}
  });

  return (
    <form action={formAction}>
      <input name="title" type="text" />
      {state.errors.title && <p className="error">{state.errors.title[0]}</p>}
      <button type="submit" disabled={isPending}>
        {isPending ? 'Creating...' : 'Create Post'}
      </button>
    </form>
  );
}

useFormStatus

Access the status of a parent <form> from any child component:

import { useFormStatus } from 'react-dom';

function SubmitButton() {
  const { pending, data, method, action } = useFormStatus();

  return (
    <button type="submit" disabled={pending}>
      {pending ? 'Submitting...' : 'Submit'}
    </button>
  );
}

// Usage - must be child of <form>
function ContactForm() {
  return (
    <form action={submitContact}>
      <input name="email" type="email" required />
      <SubmitButton />
    </form>
  );
}

Reusable Form Components

'use client';
import { useFormStatus } from 'react-dom';

export function FormButton({ children, pendingText = 'Submitting...', ...props }) {
  const { pending } = useFormStatus();

  return (
    <button {...props} disabled={pending || props.disabled}>
      {pending ? pendingText : children}
    </button>
  );
}

Full Reference: See hooks.md for useOptimistic, use() hook, Ref handling, Document Metadata.


Server Components & Server Actions

// app/users/page.tsx (Server Component by default)
export default async function UsersPage() {
  const users = await fetchUsers();
  return <UserList users={users} />;
}

// app/actions.ts
'use server';
export async function createPost(formData: FormData) {
  const title = formData.get('title') as string;
  await db.post.create({ data: { title } });
  revalidatePath('/posts');
  redirect(`/posts`);
}

Full Reference: See server.md for Server Components patterns, React Compiler, Migration Guide.


Best Practices

  • ✅ Use Actions for form submissions and mutations
  • ✅ Use useOptimistic for immediate feedback
  • ✅ Use use() instead of useEffect for data fetching
  • ✅ Let React Compiler handle memoization
  • ✅ Use Server Components for static content
  • ✅ Use Server Actions for secure mutations
  • ❌ Don't create Promises inside components for use()
  • ❌ Don't mix client/server code without proper boundaries

When NOT to Use This Skill

  • React 18 and earlier features - Use react skill instead
  • General form handling - Use react-forms or react-hook-form skills
  • Performance optimization - Use react-performance skill

Anti-Patterns

Anti-PatternProblemSolution
Creating Promises in render for use()New promise every renderCreate promise outside component
Using useFormState instead of useActionStateDeprecated in React 19Use useActionState with isPending
Missing 'use server' directiveCode runs on clientAdd 'use server' at top of file
Not validating Server Action inputsSecurity vulnerabilityAlways validate with Zod

Quick Troubleshooting

IssueLikely CauseFix
Action not workingMissing action attributeAdd action={serverAction} to form
isPending not availableUsing old useFormStateSwitch to useActionState
Serialization errorsPassing functions/classesOnly pass serializable data
ref not workingUsing old forwardRef patternPass ref as regular prop

Reference Files

FileContent
hooks.mduseOptimistic, use(), Ref handling, Metadata
server.mdServer Components, Server Actions, Compiler, Migration

External Documentation

发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

2026年9月24日

分类

未分类

许可证

MIT

源路径

skills/frontend-frameworks/react-19

默认分支

main

最新提交

9496306

Tree SHA

fe4e2f1