Skip to content
cccskills
FreePublished on GitHub

web-framework-react

Component architecture, hooks and React 19 patterns. Load when building or refactoring React components, custom hooks, forms, or async UI.

The English summary is being prepared. Showing the original description.

See how to install

Files included (6)

  • SKILL.md9.5 KB
  • examples/core.md6.2 KB
  • examples/hooks.md4.3 KB
  • examples/react-19-hooks.md10.6 KB
  • metadata.yaml395 B
  • reference.md3.8 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

React Patterns

Quick Guide: React 19 settles four things this skill turns on — ref is a regular prop and forwardRef is redundant, form submission state comes from useActionState, useFormStatus reads the enclosing form only from a child component, and a ref callback may return a cleanup function. Components stay styling-agnostic by exposing className and expressing variants as data-* attributes.

Detailed Resources:


Which path applies

  • React rendered in the browser — every pattern below applies as written, and form submission goes through useActionState in examples/react-19-hooks.md.
  • React rendered by a server framework — submission and data loading belong to that framework's own server primitives, so skip Pattern 6 and take the component, hook, ref and error-boundary patterns unchanged.

<critical_requirements>

Before writing React code

Pass ref as a regular prop. React 19 forwards it without forwardRef, which removes the wrapper and the manual displayName.

Expose className on every reusable component. It is the one seam a consumer has for styling a component this skill knows nothing about.

Call useFormStatus from a component rendered inside the <form>. Called in the component that renders the form it returns pending: false forever, with no error to show for it.

Reach for useActionState when a form needs pending or error state. It carries both, and <form action={...}> keeps working before hydration.

</critical_requirements>


Auto-detection: React 19, useActionState, useFormStatus, useOptimistic, use(), ref as prop, ref cleanup, forwardRef migration, React.ComponentProps, getDerivedStateFromError, componentDidCatch, useCallback, custom hook

Applies to:

  • Component props, composition and variant APIs
  • Migrating forwardRef components to ref-as-prop
  • Form submission, optimistic updates and promise reading with the React 19 hooks
  • Custom hooks for reusable stateful logic
  • Error boundaries with retry

Handled elsewhere:

  • Styling — a component takes className and exposes variants as data-*; which CSS approach fills them in is not its concern
  • Client state that outlives a component, and server data with its caching and invalidation — components receive both as props and stay unaware of the source
  • Routing, and the data a route loads
  • Test doubles for the network

<patterns>

Core patterns

Pattern 1: Component shape

A reusable component spreads its element's own props, accepts ref directly, and expresses variants as data-* attributes any styling layer can target.

export type ButtonProps = React.ComponentProps<"button"> & {
  variant?: "default" | "ghost" | "link";
  size?: "default" | "large" | "icon";
  ref?: React.Ref<HTMLButtonElement>;
};

export function Button({ variant = "default", size = "default", className, ref, ...props }: ButtonProps) {
  return <button className={className} data-variant={variant} data-size={size} ref={ref} {...props} />;
}

Full code: examples/core.md


Pattern 2: Typed variant props

Give a component variant props once it has two or more visual dimensions. A component with one visual style takes className and nothing else — a union with a single member is an abstraction with no second case.

export type AlertVariant = "info" | "warning" | "error" | "success";

export function Alert({ variant = "info", className, ref, ...props }: AlertProps) {
  return <div ref={ref} className={className} data-variant={variant} {...props} />;
}

Full code: examples/core.md


Pattern 3: Event handler naming

handle prefixes an internal handler (handleNameChange), on prefixes a callback prop (onSelect), and each handler types its event — FormEvent<HTMLFormElement>, ChangeEvent<HTMLInputElement> — so a wrong field access fails at compile time.

Full code: examples/core.md


Pattern 4: Custom hooks

Logic that calls hooks and renders nothing is a use-prefixed hook rather than a component: pagination state, debounced values, persisted preferences.

Full code: examples/hooks.md


Pattern 5: Error boundaries with retry

A boundary catches render errors and hands back a reset function, so a transient failure costs one section rather than the page. Place one around each feature area, not only the root.

interface Props {
  children: ReactNode;
  fallback?: (error: Error, reset: () => void) => ReactNode;
  onError?: (error: Error, errorInfo: ErrorInfo) => void;
}

A boundary is a class because there is no hook form of getDerivedStateFromError. Placement, recovery and fallback design are a subject of their own and are settled outside this skill.


Pattern 6: useActionState for form submission

The hook returns the action's last result, the action to hand <form action={...}>, and a pending flag — replacing three useState calls and their reset logic.

async function updateProfile(prevState: string | null, formData: FormData) {
  try {
    await saveProfile({ name: formData.get("name") as string });
    return null;
  } catch {
    return "Failed to save profile";
  }
}

const [error, submitAction, isPending] = useActionState(updateProfile, null);

Full code: examples/react-19-hooks.md


Pattern 7: useFormStatus for submit buttons

A submit button reads the enclosing form's pending state itself, so one button component serves every form and no form passes the flag down.

import { useFormStatus } from "react-dom";

function SubmitButton({ children }: { children: React.ReactNode }) {
  const { pending } = useFormStatus();
  return (
    <button type="submit" disabled={pending} aria-busy={pending}>
      {pending ? "Submitting..." : children}
    </button>
  );
}

Full code: examples/react-19-hooks.md


Pattern 8: useOptimistic for instant feedback

Render the expected result immediately and let React revert it if the request fails. The setter is called inside startTransition.

const [optimisticItems, addOptimistic] = useOptimistic(
  items,
  (state, update: Item) => [...state, { ...update, pending: true }],
);

startTransition(async () => {
  addOptimistic(newItem);
  await saveItem(newItem);
});

Full code: examples/react-19-hooks.md


Pattern 9: use() for promises and context

use() reads a promise or a context during render and, unlike useContext, may be called after an early return. A promise suspends until it resolves, so the caller sits under <Suspense> and a rejection is caught by an error boundary.

function Comments({ commentsPromise }: { commentsPromise: Promise<Comment[]> }) {
  const comments = use(commentsPromise);
  return <ul>{comments.map((c) => <li key={c.id}>{c.text}</li>)}</ul>;
}

<Suspense fallback={<p>Loading...</p>}>
  <Comments commentsPromise={fetchComments()} />
</Suspense>

Full code: examples/react-19-hooks.md


Pattern 10: Ref callback cleanup

A ref callback may return a cleanup function, which runs on unmount — replacing the useRef + useEffect pair for DOM setup.

<video
  ref={(video) => {
    if (!video) return;
    video.play();
    return () => {
      video.pause();
      video.currentTime = 0;
    };
  }}
  src={src}
/>

Full code: examples/react-19-hooks.md

</patterns>

<red_flags>

Red flags

Breaks at runtime:

  • useFormStatus called in the component that renders <form> — pending stays false and the button never disables; call it from a child
  • use() inside try/catch — it throws to suspend, so the catch swallows the suspension; wrap the caller in an error boundary instead
  • The useOptimistic setter called outside a transition or a form action — React rejects the call, so the optimistic value never lands
  • Browser APIs read during render under SSR — guard with typeof window !== "undefined" or move the read into an effect
  • An error boundary relied on for event-handler, async or SSR errors — it catches render errors only, so those paths carry their own try/catch

Surprising behaviour:

  • A ref callback returning anything but a cleanup function is a type error in React 19, and the callback is no longer called with null on unmount
  • useOptimistic reverts on failure by itself, so a manual rollback fights it
  • useCallback around a handler passed to a child that is not memoised costs an allocation and buys nothing; the React Compiler makes the wrapper redundant either way
  • forwardRef still compiles, so nothing flags the wrapper and its displayName as dead weight
  • A component without className cannot be styled by its consumer at all

</red_flags>

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints

The English summary is being prepared. Showing the original description.

agents-inc/skills25Updated Oct 17, 2026

LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment

The English summary is being prepared. Showing the original description.

agents-inc/skills25Updated Oct 17, 2026

Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns

The English summary is being prepared. Showing the original description.

agents-inc/skills25Updated Oct 17, 2026

Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint

The English summary is being prepared. Showing the original description.

agents-inc/skills25Updated Oct 17, 2026

Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training

The English summary is being prepared. Showing the original description.

agents-inc/skills25Updated Oct 17, 2026

Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints

The English summary is being prepared. Showing the original description.

agents-inc/skills25Updated Oct 17, 2026

See all skills by agents-inc

Report a problem with this skill