Skip to main content Accueil Créateurs chonsong skill-retriever react-patterns
react-patterns Comprehensive React 19 patterns expert covering Server Components, Actions, use() hook, useOptimistic, useFormStatus, useFormState, React Compiler, concurrent features, Suspense, and modern TypeScript development. Proactively use for any React development, component architecture, state management, performance optimization, or when implementing React 19's latest features.
Aller à l'installation Skills Marketplace Découvrez et explorez les compétences IA créées par la communauté.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Copier le promptAfficher les détails du prompt Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
npx skills add https://github.com/ChonSong/skill-retriever --skill react-patternsLa commande reste sur une seule ligne. Faites défiler horizontalement pour la vérifier avant de la copier.
Vous préférez une copie locale ? Téléchargez les fichiers actuellement disponibles dans SkillsMP.
Télécharger Zip Téléchargement... Plus depuis ce dépôt AI-powered Draw.io diagram generation with real-time browser preview. Create flowcharts, architecture diagrams, sequence diagrams, and cloud infrastructure diagrams (AWS/GCP/Azure) using natural language. Supports animated connectors, real-time editing, and structured A–H format extraction from text or images.
Multi-agent autonomous startup system for Claude Code. Triggers on "Loki Mode". Orchestrates 100+ specialized agents across engineering, QA, DevOps, security, data/ML, business operations, marketing, HR, and customer success. Takes PRD to fully deployed, revenue-generating product with zero human intervention. Features Task tool for subagent dispatch, parallel code review with 3 specialized reviewers, severity-based issue triage, distributed task queue with dead letter handling, automatic deployment to cloud providers, A/B testing, customer feedback loops, incident response, circuit breakers, and self-healing. Handles rate limits via distributed state checkpoints and auto-resume with exponential backoff. Requires --dangerously-skip-permissions flag.
When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this,"...
Métiers associés SOC
Basé sur la classification professionnelle SOC
Explorateur de fichiers
3 fichiers name react-patterns version 2.0.0 description Comprehensive React 19 patterns expert covering Server Components, Actions, use() hook, useOptimistic, useFormStatus, useFormState, React Compiler, concurrent features, Suspense, and modern TypeScript development. Proactively use for any React development, component architecture, state management, performance optimization, or when implementing React 19's latest features. language typescript,javascript,tsx,jsx framework react license MIT allowed-tools Read, Write, Edit, Bash, Grep, Glob tags ["react","react-19","typescript","javascript","jsx","tsx","hooks","server-components","actions","suspense","concurrent-rendering","react-compiler","use-optimistic","form-actions"] 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:
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):
const [state, setState] = useState (() => {
const initialState = computeExpensiveValue ();
return initialState;
});
Multiple state variables:
function UserProfile ( ) {
const [name, setName] = useState ('' );
[age, setAge] = ( );
[email, setEmail] = ( );
(
);
}
const
useState
0
const
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:
import { useEffect } from 'react' ;
function ChatRoom ({ roomId }: { roomId: string } ) {
useEffect (() => {
const connection = createConnection (roomId);
connection.connect ();
return () => {
connection.disconnect ();
};
}, [roomId]);
return <div > Connected to {roomId}</div > ;
}
Effect with multiple dependencies:
function ChatRoom ({ roomId, serverUrl }: { roomId: string ; serverUrl: string } ) {
useEffect (() => {
const connection = createConnection (serverUrl, roomId);
connection.connect ();
return () => connection.disconnect ();
}, [roomId, serverUrl]);
return <h1 > Welcome to {roomId}</h1 > ;
}
Effect for subscriptions:
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);
};
}, []);
return <h1 > {isOnline ? '✅ Online' : '❌ Disconnected'}</h1 > ;
}
useRef - Persistent References Storing mutable values without re-renders:
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 >
</>
);
}
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:
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;
}
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:
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]);
}
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:
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:
interface CardProps {
children : React .ReactNode ;
className ?: string ;
}
function Card ({ children, className = '' }: CardProps ) {
return (
<div className ={ `card ${className }`}>
{children}
</div >
);
}
function UserProfile ( ) {
return (
<Card >
<h2 > John Doe</h2 >
<p > Software Engineer</p >
</Card >
);
}
Lifting State Up Shared state between siblings:
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:
function TodoList ({ todos }: { todos: Todo[] } ) {
const [visibleTodos, setVisibleTodos] = useState<Todo []>([]);
useEffect (() => {
setVisibleTodos (todos.filter (t => !t.completed ));
}, [todos]);
return <ul > {/* ... */}</ul > ;
}
✅ Good - Compute during render:
function TodoList ({ todos }: { todos: Todo[] } ) {
const visibleTodos = todos.filter (t => !t.completed );
return <ul > {/* ... */}</ul > ;
}
useMemo for Expensive Computations import { useMemo } from 'react' ;
function DataTable ({ data }: { data: Item[] } ) {
const sortedData = useMemo (() => {
return [...data].sort ((a, b ) => a.name .localeCompare (b.name ));
}, [data]);
return <table > {/* render sortedData */}</table > ;
}
useCallback for Function Stability import { useCallback } from 'react' ;
function Parent ( ) {
const [count, setCount] = useState (0 );
const handleClick = useCallback (() => {
console .log ('Clicked' , count);
}, [count]);
return <ExpensiveChild onClick ={handleClick} /> ;
}
TypeScript Best Practices
Type-Safe Props interface UserProps {
id : string ;
name : string ;
email : string ;
age ?: number ;
}
function User ({ id, name, email, age }: UserProps ) {
return (
<div >
<h2 > {name}</h2 >
<p > {email}</p >
{age && <p > Age: {age}</p > }
</div >
);
}
Generic Components 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 >
);
}
<List
items={users}
renderItem={(user ) => <span > {user.name}</span > }
/>
Event Handlers function Form ( ) {
const handleSubmit = (e : React .FormEvent <HTMLFormElement > ) => {
e.preventDefault ();
};
const handleChange = (e : React .ChangeEvent <HTMLInputElement > ) => {
console .log (e.target .value );
};
return (
<form onSubmit ={handleSubmit} >
<input onChange ={handleChange} />
</form >
);
}
Common Patterns
Controlled Components function ControlledInput ( ) {
const [value, setValue] = useState ('' );
return (
<input
value ={value}
onChange ={e => setValue(e.target.value)}
/>
);
}
Conditional Rendering function Greeting ({ isLoggedIn }: { isLoggedIn: boolean } ) {
return (
<div >
{isLoggedIn ? (
<UserGreeting />
) : (
<GuestGreeting />
)}
</div >
);
}
Lists and Keys function UserList ({ users }: { users: User[] } ) {
return (
<ul >
{users.map(user => (
<li key ={user.id} >
{user.name}
</li >
))}
</ul >
);
}
Best Practices
General React Best Practices
Dependency Arrays : Always specify correct dependencies in useEffect
State Structure : Keep state minimal and avoid redundant state
Component Size : Keep components small and focused
Custom Hooks : Extract complex logic into reusable custom hooks
TypeScript : Use TypeScript for type safety
Keys : Use stable IDs as keys for list items, not array indices
Immutability : Never mutate state directly
Effects : Use effects only for synchronization with external systems
Performance : Profile before optimizing with useMemo/useCallback
React 19 Specific Best Practices
Server Components : Use Server Components for data fetching and static content
Client Components : Mark components as 'use client' only when necessary
Actions : Use Server Actions for mutations and form submissions
Optimistic Updates : Implement useOptimistic for better UX
use() Hook : Use for reading promises and context conditionally
Form State : Use useFormState and useFormStatus for complex forms
Concurrent Features : Leverage useTransition for non-urgent updates
Error Boundaries : Implement proper error handling with error boundaries
Common Pitfalls
General React Pitfalls useEffect (() => {
console .log (count);
}, []);
const [items, setItems] = useState ([]);
items.push (newItem);
setItems (items);
setItems ([...items, newItem]);
React 19 Specific Pitfalls ❌ Using use() outside of render :
function handleClick ( ) {
const data = use (promise);
}
function Component ({ promise } ) {
const data = use (promise);
return <div > {data}</div > ;
}
❌ Forgetting 'use server' directive :
export async function myAction ( ) {
}
'use server' ;
export async function myAction ( ) {
}
❌ Mixing Server and Client logic incorrectly :
export default async function ServerComponent ( ) {
const width = window .innerWidth ;
return <div > {width}</div > ;
}
export default async function ServerComponent ( ) {
const data = await fetchData ();
return <ClientComponent data ={data} /> ;
}
'use client' ;
function ClientComponent ({ data } ) {
const [width, setWidth] = useState (window .innerWidth );
return <div > {width}</div > ;
}
React 19 New Features
use() Hook - Reading Resources The use() hook reads the value from a resource like a Promise or Context:
import { use } from 'react' ;
function MessageComponent ({ messagePromise } ) {
const message = use (messagePromise);
return <p > {message}</p > ;
}
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:
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' ) };
addOptimisticTodo (newTodo);
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:
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:
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:
'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 ;
if (!title || !content) {
return { error : 'Title and content are required' };
}
const post = await db.post .create ({
data : { title, content }
});
revalidatePath ('/posts' );
redirect (`/posts/${post.id} ` );
}
Server Components Components that run exclusively on the server:
async function PostsPage ( ) {
const posts = await db.post .findMany ({
orderBy : { createdAt : 'desc' },
take : 10
});
return (
<div >
<h1 > Latest Posts</h1 >
<PostsList posts ={posts} />
</div >
);
}
'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:
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 >
);
});
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
npm install -D babel-plugin-react-compiler@latest
npm install -D eslint-plugin-react-hooks@latest
module .exports = {
plugins : [
'babel-plugin-react-compiler' ,
],
};
import { defineConfig } from 'vite' ;
import react from '@vitejs/plugin-react' ;
export default defineConfig ({
plugins : [
react ({
babel : {
plugins : ['babel-plugin-react-compiler' ],
},
}),
],
});
Compiler Configuration
module .exports = {
plugins : [
[
'babel-plugin-react-compiler' ,
{
target : '18' ,
debug : process.env .NODE_ENV === 'development'
}
],
],
};
module .exports = {
plugins : [],
overrides : [
{
test : './src/components/**/*.{js,jsx,ts,tsx}' ,
plugins : ['babel-plugin-react-compiler' ]
}
]
};
Advanced Server Components Patterns
Mixed Server/Client Architecture
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 >
);
}
'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 '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
) {
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 {
const order = await createOrder (result.data );
await updateInventory (result.data .items );
await sendConfirmationEmail (order);
revalidatePath ('/orders' );
return { success : true , orderId : order.id };
} catch (error) {
return { error : 'Payment failed' };
}
}
Concurrent Features
useTransition for Non-Urgent Updates 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 > ) => {
setQuery (e.target .value );
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 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 import { render, screen, fireEvent } from '@testing-library/react' ;
import { jest } from '@jest/globals' ;
import ContactForm from './ContactForm' ;
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 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' ));
expect (screen.getByText ('New todo' )).toBeInTheDocument ();
await waitFor (() => {
expect (mockAddTodo).toHaveBeenCalledWith ({
id : expect.any (Number ),
text : 'New todo'
});
});
});
});
Performance Best Practices
React Compiler Guidelines
Write Standard React Code : The compiler works best with idiomatic React patterns
Avoid Manual Memoization : Let the compiler handle useMemo, useCallback, and memo
Keep Components Pure : Avoid side effects in render
Use Stable References : Pass stable objects as props
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 >
);
}
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
Keep Server Components Server-Only : No event handlers, hooks, or browser APIs
Minimize Client Components : Only use 'use client' when necessary
Pass Data as Props : Serialize data when passing from Server to Client
Use Server Actions for Mutations : Keep data operations on the server
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 >
);
}
'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 npm install react@19 react-dom@19
Adopt Server Components :
Identify data-fetching components
Remove client-side code from Server Components
Add 'use client' directive where needed
Replace Manual Optimistic Updates :
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);
};
}
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);
};
}
Enable React Compiler :
Install babel-plugin-react-compiler
Remove manual memoization
Let the compiler optimize automatically
References