Agent skill

React Patterns

by jh941213 in jh941213/my-cc-harness

Comprehensive React 19 patterns expert covering Server Components, Actions, use() hook, useOptimistic, useFormStatus, useFormState, React Compiler, concurrent features, Suspense, and modern…

MITAuto-check: notesFrontend & Design

Install React Patterns

skills CLI
$ npx skills add jh941213/my-cc-harness --skill react-patterns -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install jh941213/my-cc-harness react-patterns --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/jh941213/my-cc-harness.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/react-patterns .claude/skills/react-patterns && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
react-patterns
GitHub stars
126
Token cost
~7.8k tokens
SKILL.md length
698 words
Files
3
Skills in repo
66
Repo updated
First seen
Licence
MIT

At a glance

Comprehensive React 19 patterns expert covering Server Components, Actions, use() hook, useOptimistic, useFormStatus, useFormState, React Compiler, concurrent features, Suspense, and modern…

  • Works in 9 steps: Dependency Arrays: Always specify… → State Structure: Keep state minimal and… → Component Size: Keep components small… → …
  • Tasks that involve React components
  • SKILL.md covers When to Use, Core Hooks Patterns, Custom Hooks Pattern and Component Composition Patterns, plus 6 more sections
  • Calls npm

What it does

React Patterns is an agent skill from jh941213/my-cc-harness. Comprehensive React 19 patterns expert covering Server Components, Actions, use() hook, useOptimistic, useFormStatus, useFormState, React Compiler, concurrent features, Suspense, and modern TypeScript development. 트리거: "React", "컴포넌트", "hooks", "JSX/TSX", "상태 관리" 안티-트리거: "Vue", "Svelte", "Angular", "백엔드"

Its SKILL.md is about 7.8k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files (for example `learn.md` and `reference.md`).

It sits in Frontend & Design, covering React components. It works with React, TypeScript, Angular and Svelte. The licence is MIT.

When your agent uses it

  • Tasks that involve React components

Example prompts

  • “JSX/TSX”
  • “Svelte”
  • “Angular”
  • “/react-patterns”

Requirements

  • Node.js
  • Pre-approved tools (allowed-tools): Read, Write, Edit, Bash, Grep, Glob

Workflow steps

9 steps, taken from the first numbered list in SKILL.md.

  1. Dependency Arrays: Always specify correct dependencies in useEffect
  2. State Structure: Keep state minimal and avoid redundant state
  3. Component Size: Keep components small and focused
  4. Custom Hooks: Extract complex logic into reusable custom hooks
  5. TypeScript: Use TypeScript for type safety
  6. Keys: Use stable IDs as keys for list items, not array indices
  7. Immutability: Never mutate state directly
  8. Effects: Use effects only for synchronization with external systems
  9. Performance: Profile before optimizing with useMemo/useCallback

What it can do on your machine

Read from SKILL.md and the folder at commit e9210e2. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves these tools, so the agent can use them without asking each time:

    • Read
    • Write
    • Edit
    • Bash
    • Grep
    • Glob

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • npm

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • react.dev
    • react-typescript-cheatsheet.netlify.app

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

React Patterns loads about 7.8k tokens when it runs. Until then it costs about 80 tokens; SKILL.md has 698 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~80
When it runs · the whole SKILL.md, loaded when a task matches
~7.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check: notes

The automated check noted patterns worth knowing about, such as sudo or a known installer.

  • NotePre-approves every shell command (allowed-tools: Bash)SKILL.md
    allowed-tools: Read, Write, Edit, Bash, Grep, Glob

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from jh941213/my-cc-harness at commit e9210e2, republished under its MIT licence (© jh941213). 698 words, ~7,846 tokens.

Download SKILL.mdSave it as .claude/skills/react-patterns/SKILL.md (or your agent's skills folder). This skill also uses 2 other files; get the full folder from GitHub.
name
react-patterns
description
Comprehensive React 19 patterns expert covering Server Components, Actions, use() hook, useOptimistic, useFormStatus, useFormState, React Compiler, concurrent features, Suspense, and modern TypeScript development. 트리거: "React", "컴포넌트", "hooks", "JSX/TSX", "상태 관리" 안티-트리거: "Vue", "Svelte", "Angular", "백엔드"
allowed-tools
Read, Write, Edit, Bash, Grep, Glob
version
2.0.0
user-invocable
false
language
typescript,javascript,tsx,jsx
framework
react
license
MIT
tags
react, react-19, typescript, javascript, jsx, tsx, hooks, server-components, actions, suspense, concurrent-rendering, react-compiler, use-optimistic…
category
frontend
subcategories
components, hooks, state-management, performance, server-components, forms, testing

React Development Patterns

Expert guide for building modern React 19 applications with new concurrent features, Server Components, Actions, and advanced patterns.

When to Use

  • Building React 19 components with TypeScript/JavaScript
  • Managing component state with useState and useReducer
  • Handling side effects with useEffect
  • Optimizing performance with useMemo and useCallback
  • Creating custom hooks for reusable logic
  • Implementing component composition patterns
  • Working with refs using useRef
  • Using React 19's new features (use(), useOptimistic, useFormStatus)
  • Implementing Server Components and Actions
  • Working with Suspense and concurrent rendering
  • Building forms with new form hooks

Core Hooks Patterns

useState - State Management

Basic state declaration and updates:

typescript
import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

State with initializer function (expensive computation):

typescript
const [state, setState] = useState(() => {
  const initialState = computeExpensiveValue();
  return initialState;
});

Multiple state variables:

typescript
function UserProfile() {
  const [name, setName] = useState('');
  const [age, setAge] = useState(0);
  const [email, setEmail] = useState('');
  
  return (
    <form>
      <input value={name} onChange={e => setName(e.target.value)} />
      <input type="number" value={age} onChange={e => setAge(Number(e.target.value))} />
      <input type="email" value={email} onChange={e => setEmail(e.target.value)} />
    </form>
  );
}
useEffect - Side Effects

Basic effect with cleanup:

typescript
import { useEffect } from 'react';

function ChatRoom({ roomId }: { roomId: string }) {
  useEffect(() => {
    const connection = createConnection(roomId);
    connection.connect();
    
    // Cleanup function
    return () => {
      connection.disconnect();
    };
  }, [roomId]); // Dependency array
  
  return <div>Connected to {roomId}</div>;
}

Effect with multiple dependencies:

typescript
function ChatRoom({ roomId, serverUrl }: { roomId: string; serverUrl: string }) {
  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.connect();
    
    return () => connection.disconnect();
  }, [roomId, serverUrl]); // Re-run when either changes
  
  return <h1>Welcome to {roomId}</h1>;
}

Effect for subscriptions:

typescript
function StatusBar() {
  const [isOnline, setIsOnline] = useState(true);
  
  useEffect(() => {
    function handleOnline() {
      setIsOnline(true);
    }
    
    function handleOffline() {
      setIsOnline(false);
    }
    
    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);
    
    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []); // Empty array = run once on mount
  
  return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;
}
useRef - Persistent References

Storing mutable values without re-renders:

typescript
import { useRef } from 'react';

function Timer() {
  const intervalRef = useRef<NodeJS.Timeout | null>(null);
  
  const startTimer = () => {
    intervalRef.current = setInterval(() => {
      console.log('Tick');
    }, 1000);
  };
  
  const stopTimer = () => {
    if (intervalRef.current) {
      clearInterval(intervalRef.current);
    }
  };
  
  return (
    <>
      <button onClick={startTimer}>Start</button>
      <button onClick={stopTimer}>Stop</button>
    </>
  );
}

DOM element references:

typescript
function TextInput() {
  const inputRef = useRef<HTMLInputElement>(null);
  
  const focusInput = () => {
    inputRef.current?.focus();
  };
  
  return (
    <>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>Focus Input</button>
    </>
  );
}

Custom Hooks Pattern

Extract reusable logic into custom hooks:

typescript
// useOnlineStatus.ts
import { useState, useEffect } from 'react';

export function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(true);
  
  useEffect(() => {
    function handleOnline() {
      setIsOnline(true);
    }
    
    function handleOffline() {
      setIsOnline(false);
    }
    
    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);
    
    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);
  
  return isOnline;
}

// Usage in components
function StatusBar() {
  const isOnline = useOnlineStatus();
  return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;
}

function SaveButton() {
  const isOnline = useOnlineStatus();
  return (
    <button disabled={!isOnline}>
      {isOnline ? 'Save' : 'Reconnecting...'}
    </button>
  );
}

Custom hook with parameters:

typescript
// useChatRoom.ts
import { useEffect } from 'react';

interface ChatOptions {
  serverUrl: string;
  roomId: string;
}

export function useChatRoom({ serverUrl, roomId }: ChatOptions) {
  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.connect();
    
    return () => connection.disconnect();
  }, [serverUrl, roomId]);
}

// Usage
function ChatRoom({ roomId }: { roomId: string }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:1234');
  
  useChatRoom({ serverUrl, roomId });
  
  return (
    <>
      <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} />
      <h1>Welcome to {roomId}</h1>
    </>
  );
}

Component Composition Patterns

Props and Children

Basic component with props:

typescript
interface ButtonProps {
  variant?: 'primary' | 'secondary';
  size?: 'sm' | 'md' | 'lg';
  onClick?: () => void;
  children: React.ReactNode;
}

function Button({ variant = 'primary', size = 'md', onClick, children }: ButtonProps) {
  return (
    <button 
      className={`btn btn-${variant} btn-${size}`}
      onClick={onClick}
    >
      {children}
    </button>
  );
}

Composition with children:

typescript
interface CardProps {
  children: React.ReactNode;
  className?: string;
}

function Card({ children, className = '' }: CardProps) {
  return (
    <div className={`card ${className}`}>
      {children}
    </div>
  );
}

// Usage
function UserProfile() {
  return (
    <Card>
      <h2>John Doe</h2>
      <p>Software Engineer</p>
    </Card>
  );
}
Lifting State Up

Shared state between siblings:

typescript
function Parent() {
  const [activeIndex, setActiveIndex] = useState(0);
  
  return (
    <>
      <Panel
        isActive={activeIndex === 0}
        onShow={() => setActiveIndex(0)}
      >
        Panel 1 content
      </Panel>
      <Panel
        isActive={activeIndex === 1}
        onShow={() => setActiveIndex(1)}
      >
        Panel 2 content
      </Panel>
    </>
  );
}

interface PanelProps {
  isActive: boolean;
  onShow: () => void;
  children: React.ReactNode;
}

function Panel({ isActive, onShow, children }: PanelProps) {
  return (
    <div>
      <button onClick={onShow}>Show</button>
      {isActive && <div>{children}</div>}
    </div>
  );
}

Performance Optimization

Avoid Unnecessary Effects

❌ Bad - Using effect for derived state:

typescript
function TodoList({ todos }: { todos: Todo[] }) {
  const [visibleTodos, setVisibleTodos] = useState<Todo[]>([]);
  
  useEffect(() => {
    setVisibleTodos(todos.filter(t => !t.completed));
  }, [todos]); // Unnecessary effect
  
  return <ul>{/* ... */}</ul>;
}

✅ Good - Compute during render:

typescript
function TodoList({ todos }: { todos: Todo[] }) {
  const visibleTodos = todos.filter(t => !t.completed); // Direct computation
  
  return <ul>{/* ... */}</ul>;
}
useMemo for Expensive Computations
typescript
import { useMemo } from 'react';

function DataTable({ data }: { data: Item[] }) {
  const sortedData = useMemo(() => {
    return [...data].sort((a, b) => a.name.localeCompare(b.name));
  }, [data]); // Only recompute when data changes
  
  return <table>{/* render sortedData */}</table>;
}
useCallback for Function Stability
typescript
import { useCallback } from 'react';

function Parent() {
  const [count, setCount] = useState(0);
  
  const handleClick = useCallback(() => {
    console.log('Clicked', count);
  }, [count]); // Recreate only when count changes
  
  return <ExpensiveChild onClick={handleClick} />;
}

TypeScript Best Practices

Type-Safe Props
typescript
interface UserProps {
  id: string;
  name: string;
  email: string;
  age?: number; // Optional
}

function User({ id, name, email, age }: UserProps) {
  return (
    <div>
      <h2>{name}</h2>
      <p>{email}</p>
      {age && <p>Age: {age}</p>}
    </div>
  );
}
Generic Components
typescript
interface ListProps<T> {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
}

function List<T>({ items, renderItem }: ListProps<T>) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{renderItem(item)}</li>
      ))}
    </ul>
  );
}

// Usage
<List 
  items={users}
  renderItem={(user) => <span>{user.name}</span>}
/>
Event Handlers
typescript
function Form() {
  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    // Handle form submission
  };
  
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    console.log(e.target.value);
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input onChange={handleChange} />
    </form>
  );
}

Common Patterns

Controlled Components
typescript
function ControlledInput() {
  const [value, setValue] = useState('');
  
  return (
    <input 
      value={value}
      onChange={e => setValue(e.target.value)}
    />
  );
}
Conditional Rendering
typescript
function Greeting({ isLoggedIn }: { isLoggedIn: boolean }) {
  return (
    <div>
      {isLoggedIn ? (
        <UserGreeting />
      ) : (
        <GuestGreeting />
      )}
    </div>
  );
}
Lists and Keys
typescript
function UserList({ users }: { users: User[] }) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>
          {user.name}
        </li>
      ))}
    </ul>
  );
}

Best Practices

General React Best Practices
  1. Dependency Arrays: Always specify correct dependencies in useEffect
  2. State Structure: Keep state minimal and avoid redundant state
  3. Component Size: Keep components small and focused
  4. Custom Hooks: Extract complex logic into reusable custom hooks
  5. TypeScript: Use TypeScript for type safety
  6. Keys: Use stable IDs as keys for list items, not array indices
  7. Immutability: Never mutate state directly
  8. Effects: Use effects only for synchronization with external systems
  9. Performance: Profile before optimizing with useMemo/useCallback
React 19 Specific Best Practices
  1. Server Components: Use Server Components for data fetching and static content
  2. Client Components: Mark components as 'use client' only when necessary
  3. Actions: Use Server Actions for mutations and form submissions
  4. Optimistic Updates: Implement useOptimistic for better UX
  5. use() Hook: Use for reading promises and context conditionally
  6. Form State: Use useFormState and useFormStatus for complex forms
  7. Concurrent Features: Leverage useTransition for non-urgent updates
  8. Error Boundaries: Implement proper error handling with error boundaries

Common Pitfalls

General React Pitfalls

❌ Missing Dependencies:

typescript
useEffect(() => {
  // Uses 'count' but doesn't include it in deps
  console.log(count);
}, []); // Wrong!

❌ Mutating State:

typescript
const [items, setItems] = useState([]);
items.push(newItem); // Wrong! Mutates state
setItems(items); // Won't trigger re-render

✅ Correct Approach:

typescript
setItems([...items, newItem]); // Create new array
React 19 Specific Pitfalls

❌ Using use() outside of render:

typescript
// Wrong!
function handleClick() {
  const data = use(promise); // Error: use() can only be called in render
}

✅ Correct usage:

tsx
function Component({ promise }) {
  const data = use(promise); // Correct: called during render
  return <div>{data}</div>;
}

❌ Forgetting 'use server' directive:

typescript
// Wrong - missing 'use server'
export async function myAction() {
  // This will run on the client!
}

✅ Correct Server Action:

typescript
'use server'; // Must be at the top

export async function myAction() {
  // Now runs on the server
}

❌ Mixing Server and Client logic incorrectly:

tsx
// Wrong - trying to use browser APIs in Server Component
export default async function ServerComponent() {
  const width = window.innerWidth; // Error: window is not defined
  return <div>{width}</div>;
}

✅ Correct separation:

tsx
// Server Component for data
export default async function ServerComponent() {
  const data = await fetchData();
  return <ClientComponent data={data} />;
}

// Client Component for browser APIs
'use client';

function ClientComponent({ data }) {
  const [width, setWidth] = useState(window.innerWidth);
  // Handle resize logic...
  return <div>{width}</div>;
}

React 19 New Features

Show full SKILL.md (280 more words)Show less
use() Hook - Reading Resources

The use() hook reads the value from a resource like a Promise or Context:

typescript
import { use } from 'react';

// Reading a Promise in a component
function MessageComponent({ messagePromise }) {
  const message = use(messagePromise);
  return <p>{message}</p>;
}

// Reading Context conditionally
function Button() {
  if (condition) {
    const theme = use(ThemeContext);
    return <button className={theme}>Click</button>;
  }
  return <button>Click</button>;
}
useOptimistic Hook - Optimistic UI Updates

Manage optimistic UI updates for async operations:

typescript
import { useOptimistic } from 'react';

function TodoList({ todos, addTodo }) {
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo) => [...state, newTodo]
  );

  const handleSubmit = async (formData) => {
    const newTodo = { id: Date.now(), text: formData.get('text') };

    // Optimistically add to UI
    addOptimisticTodo(newTodo);

    // Actually add to backend
    await addTodo(newTodo);
  };

  return (
    <form action={handleSubmit}>
      {optimisticTodos.map(todo => (
        <div key={todo.id}>{todo.text}</div>
      ))}
      <input type="text" name="text" />
      <button type="submit">Add Todo</button>
    </form>
  );
}
useFormStatus Hook - Form State

Access form submission status from child components:

typescript
import { useFormStatus } from 'react';

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

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

function ContactForm() {
  return (
    <form action={submitForm}>
      <input name="email" type="email" />
      <SubmitButton />
    </form>
  );
}
useFormState Hook - Form State Management

Manage form state with error handling:

typescript
import { useFormState } from 'react';

async function submitAction(prevState: string | null, formData: FormData) {
  const email = formData.get('email') as string;

  if (!email.includes('@')) {
    return 'Invalid email address';
  }

  await submitToDatabase(email);
  return null;
}

function EmailForm() {
  const [state, formAction] = useFormState(submitAction, null);

  return (
    <form action={formAction}>
      <input name="email" type="email" />
      <button type="submit">Subscribe</button>
      {state && <p className="error">{state}</p>}
    </form>
  );
}
Server Actions

Define server-side functions for form handling:

typescript
// app/actions.ts
'use server';

import { redirect } from 'next/navigation';
import { revalidatePath } from 'next/cache';

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string;
  const content = formData.get('content') as string;

  // Validate input
  if (!title || !content) {
    return { error: 'Title and content are required' };
  }

  // Save to database
  const post = await db.post.create({
    data: { title, content }
  });

  // Update cache and redirect
  revalidatePath('/posts');
  redirect(`/posts/${post.id}`);
}
Server Components

Components that run exclusively on the server:

typescript
// app/posts/page.tsx - Server Component
async function PostsPage() {
  // Server-side data fetching
  const posts = await db.post.findMany({
    orderBy: { createdAt: 'desc' },
    take: 10
  });

  return (
    <div>
      <h1>Latest Posts</h1>
      <PostsList posts={posts} />
    </div>
  );
}

// Client Component for interactivity
'use client';

function PostsList({ posts }: { posts: Post[] }) {
  const [selectedId, setSelectedId] = useState<number | null>(null);

  return (
    <ul>
      {posts.map(post => (
        <li
          key={post.id}
          onClick={() => setSelectedId(post.id)}
          className={selectedId === post.id ? 'selected' : ''}
        >
          {post.title}
        </li>
      ))}
    </ul>
  );
}

React Compiler

Automatic Optimization

React Compiler automatically optimizes your components:

typescript
// Before React Compiler - manual memoization needed
const ExpensiveComponent = memo(function ExpensiveComponent({
  data,
  onUpdate
}) {
  const processedData = useMemo(() => {
    return data.map(item => ({
      ...item,
      computed: expensiveCalculation(item)
    }));
  }, [data]);

  const handleClick = useCallback((id) => {
    onUpdate(id);
  }, [onUpdate]);

  return (
    <div>
      {processedData.map(item => (
        <Item
          key={item.id}
          item={item}
          onClick={handleClick}
        />
      ))}
    </div>
  );
});

// After React Compiler - no manual optimization needed
function ExpensiveComponent({ data, onUpdate }) {
  const processedData = data.map(item => ({
    ...item,
    computed: expensiveCalculation(item)
  }));

  const handleClick = (id) => {
    onUpdate(id);
  };

  return (
    <div>
      {processedData.map(item => (
        <Item
          key={item.id}
          item={item}
          onClick={handleClick}
        />
      ))}
    </div>
  );
}
Installation and Setup
bash
# Install React Compiler
npm install -D babel-plugin-react-compiler@latest

# Install ESLint plugin for validation
npm install -D eslint-plugin-react-hooks@latest
javascript
// babel.config.js
module.exports = {
  plugins: [
    'babel-plugin-react-compiler', // Must run first!
    // ... other plugins
  ],
};
javascript
// vite.config.js for Vite users
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: ['babel-plugin-react-compiler'],
      },
    }),
  ],
});
Compiler Configuration
javascript
// babel.config.js with compiler options
module.exports = {
  plugins: [
    [
      'babel-plugin-react-compiler',
      {
        // Enable compilation for specific files
        target: '18', // or '19'
        // Debug mode for development
        debug: process.env.NODE_ENV === 'development'
      }
    ],
  ],
};

// Incremental adoption with overrides
module.exports = {
  plugins: [],
  overrides: [
    {
      test: './src/components/**/*.{js,jsx,ts,tsx}',
      plugins: ['babel-plugin-react-compiler']
    }
  ]
};

Advanced Server Components Patterns

Mixed Server/Client Architecture
typescript
// Server Component for data fetching
async function ProductPage({ id }: { id: string }) {
  const product = await fetchProduct(id);
  const related = await fetchRelatedProducts(id);

  return (
    <div>
      <ProductDetails product={product} />
      <ProductGallery images={product.images} />
      <RelatedProducts products={related} />
    </div>
  );
}

// Client Component for interactivity
'use client';

function ProductDetails({ product }: { product: Product }) {
  const [quantity, setQuantity] = useState(1);
  const [isAdded, setIsAdded] = useState(false);

  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <p>${product.price}</p>

      <QuantitySelector
        value={quantity}
        onChange={setQuantity}
      />

      <AddToCartButton
        productId={product.id}
        quantity={quantity}
        onAdded={() => setIsAdded(true)}
      />

      {isAdded && <p>Added to cart!</p>}
    </div>
  );
}
Server Actions with Validation
typescript
'use server';

import { z } from 'zod';

const checkoutSchema = z.object({
  items: z.array(z.object({
    productId: z.string(),
    quantity: z.number().min(1)
  })),
  shippingAddress: z.object({
    street: z.string().min(1),
    city: z.string().min(1),
    zipCode: z.string().regex(/^\d{5}$/)
  }),
  paymentMethod: z.enum(['credit', 'paypal', 'apple'])
});

export async function processCheckout(
  prevState: any,
  formData: FormData
) {
  // Extract and validate data
  const rawData = {
    items: JSON.parse(formData.get('items') as string),
    shippingAddress: {
      street: formData.get('street'),
      city: formData.get('city'),
      zipCode: formData.get('zipCode')
    },
    paymentMethod: formData.get('paymentMethod')
  };

  const result = checkoutSchema.safeParse(rawData);

  if (!result.success) {
    return {
      error: 'Validation failed',
      fieldErrors: result.error.flatten().fieldErrors
    };
  }

  try {
    // Process payment
    const order = await createOrder(result.data);

    // Update inventory
    await updateInventory(result.data.items);

    // Send confirmation
    await sendConfirmationEmail(order);

    // Revalidate cache
    revalidatePath('/orders');

    return { success: true, orderId: order.id };
  } catch (error) {
    return { error: 'Payment failed' };
  }
}

Concurrent Features

useTransition for Non-Urgent Updates
typescript
import { useTransition, useState } from 'react';

function SearchableList({ items }: { items: Item[] }) {
  const [query, setQuery] = useState('');
  const [isPending, startTransition] = useTransition();
  const [filteredItems, setFilteredItems] = useState(items);

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    // Update input immediately
    setQuery(e.target.value);

    // Transition the filter operation
    startTransition(() => {
      setFilteredItems(
        items.filter(item =>
          item.name.toLowerCase().includes(e.target.value.toLowerCase())
        )
      );
    });
  };

  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={handleChange}
        placeholder="Search items..."
      />

      {isPending && <div className="loading">Filtering...</div>}

      <ul>
        {filteredItems.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}
useDeferredValue for Expensive UI
typescript
import { useDeferredValue, useMemo } from 'react';

function DataGrid({ data }: { data: DataRow[] }) {
  const [searchTerm, setSearchTerm] = useState('');
  const deferredSearchTerm = useDeferredValue(searchTerm);

  const filteredData = useMemo(() => {
    return data.filter(row =>
      Object.values(row).some(value =>
        String(value).toLowerCase().includes(deferredSearchTerm.toLowerCase())
      )
    );
  }, [data, deferredSearchTerm]);

  return (
    <div>
      <input
        value={searchTerm}
        onChange={e => setSearchTerm(e.target.value)}
        placeholder="Search..."
        className={searchTerm !== deferredSearchTerm ? 'stale' : ''}
      />

      <DataGridRows
        data={filteredData}
        isStale={searchTerm !== deferredSearchTerm}
      />
    </div>
  );
}

Testing React 19 Features

Testing Server Actions
typescript
import { render, screen, fireEvent } from '@testing-library/react';
import { jest } from '@jest/globals';
import ContactForm from './ContactForm';

// Mock server action
const mockSubmitForm = jest.fn();

describe('ContactForm', () => {
  it('submits form with server action', async () => {
    render(<ContactForm />);

    fireEvent.change(screen.getByLabelText('Email'), {
      target: { value: 'test@example.com' }
    });

    fireEvent.click(screen.getByText('Submit'));

    expect(mockSubmitForm).toHaveBeenCalledWith(
      expect.any(FormData)
    );
  });

  it('shows loading state during submission', async () => {
    mockSubmitForm.mockImplementation(() => new Promise(resolve => setTimeout(resolve, 100)));

    render(<ContactForm />);

    fireEvent.click(screen.getByText('Submit'));

    expect(screen.getByText('Submitting...')).toBeInTheDocument();

    await waitFor(() => {
      expect(screen.getByText('Submit')).toBeInTheDocument();
    });
  });
});
Testing Optimistic Updates
typescript
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { jest } from '@jest/globals';
import TodoList from './TodoList';

describe('useOptimistic', () => {
  it('shows optimistic update immediately', async () => {
    const mockAddTodo = jest.fn(() => new Promise(resolve => setTimeout(resolve, 100)));

    render(
      <TodoList
        todos={[]}
        addTodo={mockAddTodo}
      />
    );

    fireEvent.change(screen.getByPlaceholderText('Add a todo'), {
      target: { value: 'New todo' }
    });

    fireEvent.click(screen.getByText('Add'));

    // Optimistic update appears immediately
    expect(screen.getByText('New todo')).toBeInTheDocument();

    // Wait for actual submission
    await waitFor(() => {
      expect(mockAddTodo).toHaveBeenCalledWith({
        id: expect.any(Number),
        text: 'New todo'
      });
    });
  });
});

Performance Best Practices

React Compiler Guidelines
  1. Write Standard React Code: The compiler works best with idiomatic React patterns
  2. Avoid Manual Memoization: Let the compiler handle useMemo, useCallback, and memo
  3. Keep Components Pure: Avoid side effects in render
  4. Use Stable References: Pass stable objects as props
typescript
// Good: Clean, idiomatic React
function ProductCard({ product, onAddToCart }) {
  const [quantity, setQuantity] = useState(1);

  const handleAdd = () => {
    onAddToCart(product.id, quantity);
  };

  return (
    <div>
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      <input
        type="number"
        value={quantity}
        onChange={e => setQuantity(Number(e.target.value))}
        min="1"
      />
      <button onClick={handleAdd}>Add to Cart</button>
    </div>
  );
}

// Avoid: Manual optimization
function ProductCard({ product, onAddToCart }) {
  const [quantity, setQuantity] = useState(1);

  const handleAdd = useCallback(() => {
    onAddToCart(product.id, quantity);
  }, [product.id, quantity, onAddToCart]);

  return (
    <div>
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      <QuantityInput
        value={quantity}
        onChange={setQuantity}
      />
      <button onClick={handleAdd}>Add to Cart</button>
    </div>
  );
}
Server Components Best Practices
  1. Keep Server Components Server-Only: No event handlers, hooks, or browser APIs
  2. Minimize Client Components: Only use 'use client' when necessary
  3. Pass Data as Props: Serialize data when passing from Server to Client
  4. Use Server Actions for Mutations: Keep data operations on the server
typescript
// Good: Server Component for static content
async function ProductPage({ id }: { id: string }) {
  const product = await fetchProduct(id);

  return (
    <article>
      <header>
        <h1>{product.name}</h1>
        <p>{product.description}</p>
      </header>

      <img
        src={product.imageUrl}
        alt={product.name}
        width={600}
        height={400}
      />

      <PriceDisplay price={product.price} />
      <AddToCartForm productId={product.id} />
    </article>
  );
}

// Client Component only for interactivity
'use client';

function AddToCartForm({ productId }: { productId: string }) {
  const [isAdding, setIsAdding] = useState(false);

  async function handleSubmit() {
    setIsAdding(true);
    await addToCart(productId);
    setIsAdding(false);
  }

  return (
    <form action={handleSubmit}>
      <button type="submit" disabled={isAdding}>
        {isAdding ? 'Adding...' : 'Add to Cart'}
      </button>
    </form>
  );
}

Migration Guide

From React 18 to 19
  1. Update Dependencies:
bash
npm install react@19 react-dom@19
  1. Adopt Server Components:

    • Identify data-fetching components
    • Remove client-side code from Server Components
    • Add 'use client' directive where needed
  2. Replace Manual Optimistic Updates:

typescript
// Before
function TodoList({ todos, addTodo }) {
  const [optimisticTodos, setOptimisticTodos] = useState(todos);

  const handleAdd = async (text) => {
    const newTodo = { id: Date.now(), text };
    setOptimisticTodos([...optimisticTodos, newTodo]);
    await addTodo(newTodo);
  };
}

// After
function TodoList({ todos, addTodo }) {
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo) => [...state, newTodo]
  );

  const handleAdd = async (formData) => {
    const newTodo = { id: Date.now(), text: formData.get('text') };
    addOptimisticTodo(newTodo);
    await addTodo(newTodo);
  };
}
  1. Enable React Compiler:
    • Install babel-plugin-react-compiler
    • Remove manual memoization
    • Let the compiler optimize automatically

References

© jh941213, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 2 other files in skills/react-patterns of jh941213/my-cc-harness.

  • SKILL.md
  • learn.md
  • reference.md

Open the folder on GitHubat commit e9210e2

Compare with similar skills

React Patterns next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

React Patterns compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
React Patterns this skilljh941213/my-cc-harness126—~7.8kAutomated safety check: NotesMIT
Boneyard0xGF/boneyard7.5k—~2.2kAutomated safety check: NotesMIT
Markstream InstallSimon-He95/markstream-vue3k—~2.2kAutomated safety check: PassMIT
Solar Iconssaoudi-h/solar-icons182—~2.1kAutomated safety check: PassMIT
Tailwind To Stylexshadcn-labs/shadcn-cssinjs122—~2.7kAutomated safety check: PassMIT
Component ForgeEliasOulkadi/shokunin114—~3.6kAutomated safety check: NotesMIT

Similar skills

  • Boneyard

    0xGF/boneyard

    Use boneyard-js to add, configure, debug, or rebuild skeleton screens.

    7.5k GitHub stars~2.2k tokensUpdated 1 mo ago
    Frontend & DesignAuto-check: notes
  • Markstream Install

    Simon-He95/markstream-vue

    Install and wire markstream-vue, markstream-react, markstream-vue2, markstream-angular, or markstream-svelte into an existing repository.

    3k GitHub stars~2.2k tokensUpdated 2 days ago
    Frontend & DesignAuto-check passed
  • Solar Icons

    saoudi-h/solar-icons

    Add Solar Icons via @solar-icons/cli to any React, Vue, Svelte, Solid, Angular, React Native, Nuxt, Static, vanilla JS, or Laravel Blade project.

    182 GitHub stars~2.1k tokensUpdated yesterday
    Frontend & DesignAuto-check passed
  • Tailwind To Stylex

    shadcn-labs/shadcn-cssinjs

    Migrate TailwindCSS to StyleX. An agent skill from shadcn-labs/shadcn-cssinjs.

    122 GitHub stars~2.7k tokensUpdated 26 days ago
    Frontend & DesignAuto-check passed
  • Component Forge

    EliasOulkadi/shokunin

    Build production-grade components for React, Vue 3, and Svelte 5 with all states (loading, empty, error, success, idle), TypeScript strict, WCAG 2.2 accessibility, server components (RSC), and…

    114 GitHub stars~3.6k tokensUpdated 2 days ago
    Frontend & DesignAuto-check: notes
  • Kb Web Scanning

    Community-Access/accessibility-agents

    Reference data, not a reviewer. An agent skill from Community-Access/accessibility-agents.

    421 GitHub stars~1.2k tokensUpdated 14 days ago
    Frontend & DesignAuto-check passed

More from jh941213/my-cc-harness

All 66 skills in this repo
  • API Design Principles

    jh941213/my-cc-harness

    REST 및 GraphQL API 설계 원칙 가이드. An agent skill from jh941213/my-cc-harness.

    126 GitHub starsUsed in 19 repos~3.4k tokens
    Auto-check passed
  • Tailwind Design System

    jh941213/my-cc-harness

    Build scalable design systems with Tailwind CSS, design tokens, component libraries, and responsive patterns.

    126 GitHub starsUsed in 9 repos~4.7k tokens
    Auto-check passed
  • Docs Architecture

    jh941213/my-cc-harness

    Generate/update architecture docs — ARCHITECTURE.md (codemap), architecture diagrams (C4 mermaid), ADRs (MADR), data model ERD.

    126 GitHub stars~923 tokensUpdated 2 mo ago
    Auto-check: notes
  • Auto Memory

    jh941213/my-cc-harness

    A skill your agent uses when starting substantial work in a repo (implementation, fixes, deploys, debugging), when first exploring a new repo, or when finishing work that produced reusable knowledge.

    126 GitHub stars~890 tokensUpdated 2 mo ago
    Auto-check passed
  • Autodev

    jh941213/my-cc-harness

    Ralph Loop based autonomous development loop. An agent skill from jh941213/my-cc-harness.

    126 GitHub stars~1.5k tokensUpdated 2 mo ago
    Auto-check: notes
  • Async Python Patterns

    jh941213/my-cc-harness

    Python asyncio 및 async/await 패턴 가이드. An agent skill from jh941213/my-cc-harness.

    126 GitHub starsUsed in 13 repos~4.7k tokens
    Auto-check passed

Questions about React Patterns

What does React Patterns do?

Comprehensive React 19 patterns expert covering Server Components, Actions, use() hook, useOptimistic, useFormStatus, useFormState, React Compiler, concurrent features, Suspense, and modern…. React Patterns is an agent skill from jh941213/my-cc-harness. Comprehensive React 19 patterns expert covering Server Components, Actions, use() hook, useOptimistic, useFormStatus, useFormState, React Compiler, concurrent features, Suspense, and modern TypeScript development.

When should I use React Patterns?

React Patterns fits situations like: tasks that involve React components.

How do I install React Patterns in Claude Code?

Run `npx skills add jh941213/my-cc-harness --skill react-patterns -a claude-code`. Or copy the skill folder (skills/react-patterns in jh941213/my-cc-harness) into .claude/skills/react-patterns in your project. Claude Code loads it when a task matches its description.

How do I install React Patterns in Codex?

Run `npx skills add jh941213/my-cc-harness --skill react-patterns -a codex`. Or copy the skill folder (skills/react-patterns in jh941213/my-cc-harness) into .agents/skills/react-patterns in your project. Codex loads it when a task matches its description.

Can I use React Patterns in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add jh941213/my-cc-harness --skill react-patterns -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/react-patterns, .gemini/skills/react-patterns, .github/skills/react-patterns and .opencode/skills/react-patterns in your project.

What does React Patterns need to run?

Going by SKILL.md and its folder, React Patterns needs the command-line tools its instructions call (npm). Our summary lists: Node.js. Its frontmatter pre-approves these tools: Read, Write, Edit, Bash, Grep, Glob.

Does React Patterns access the network?

SKILL.md names 2 domains. As links in the text: react.dev and react-typescript-cheatsheet.netlify.app. This is read from the text; nothing was executed.

Is React Patterns safe to install?

Our automated static check of SKILL.md found notes only (pre-approves every shell command (allowed-tools: bash)), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.

What licence does React Patterns use?

React Patterns is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does React Patterns use?

About 7.8k tokens (SKILL.md is roughly 31k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to React Patterns?

Skills that share tags, products or a category with React Patterns: Boneyard (0xGF/boneyard, 7.5k stars), Markstream Install (Simon-He95/markstream-vue, 3k stars), Solar Icons (saoudi-h/solar-icons, 182 stars) and Tailwind To Stylex (shadcn-labs/shadcn-cssinjs, 122 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains React Patterns?

jh941213 (a GitHub user) maintains it in jh941213/my-cc-harness, which has 126 GitHub stars. The repository holds 66 skills in this directory. The repository was last updated on August 3, 2026.

Source: jh941213/my-cc-harness on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.