React logoReact ADVANCED

React Design Patterns

Advanced React patterns for state management, concurrent rendering, React 19 Actions, and Server Components

10 min read
reactpatternsreact-19concurrentserver-componentsactionsstate-managementreduceroptimistic-ui

State Management Patterns

Patterns for managing complex state with reducers, context, and custom hooks

useReducer Pattern

Manage complex state transitions with a reducer function and dispatched actions

jsx
💡 useReducer centralizes state logic — pure functions are easy to test in isolation
⚡ Action types should describe WHAT happened (user_added) not HOW to update (setUser)
📌 Pass an init function as the third arg for lazy initialization of expensive state
🟢 Use useReducer when state has 3+ sub-values or complex transitions — useState otherwise
useReducerstatereducer

Reducer + Context Pattern

Combine useReducer with Context to share complex state across the component tree (Redux-lite)

jsx
💡 Split state and dispatch into TWO contexts so dispatchers do not re-render on state changes
⚡ Wrap useContext in custom hooks (useTasks, useTasksDispatch) for ergonomics and type safety
📌 This is the standard "Redux without Redux" pattern — perfect for app-wide state without libraries
🟢 dispatch is stable across renders, so components that only dispatch never re-render unnecessarily
reducercontextstate-management

Custom Hooks Composition

Build complex behavior by composing smaller, focused custom hooks

jsx
💡 Custom hooks compose freely — useDebouncedSearch is just useDebounce + useFetch
⚡ Each hook should do ONE thing well — composition handles the complex cases
📌 Return objects when destructuring is more readable; arrays for tuple-like APIs
🟢 Always use the cancelled flag pattern in async effects to avoid memory leaks
custom-hookscomposition

Concurrent Rendering

Use React concurrent features to keep the UI responsive during expensive updates

useTransition

Mark state updates as non-urgent transitions to keep the UI responsive

jsx
💡 useTransition tells React "this update is not urgent — keep the UI responsive"
⚡ Use it for tab switches, search filtering, and any heavy re-render triggered by user input
📌 React 19 supports async functions inside startTransition — perfect for form submissions
🟢 isPending lets you show subtle loading hints without blocking the click feedback
useTransitionconcurrentpending

useDeferredValue

Defer rendering of expensive UI based on a value while keeping inputs responsive

jsx
💡 useDeferredValue defers a VALUE; useTransition defers an UPDATE — pick based on what you control
⚡ Always memoize the expensive child — otherwise React still re-renders it on every keystroke
📌 Compare value !== deferredValue to detect stale state and show a visual hint
🟢 React renders twice: once with the old value, then again in the background with the new one
useDeferredValueconcurrentperformance

React 19 Actions & Forms

New form handling pattern with built-in pending state, errors, and optimistic updates

useActionState

Manage form state, errors, and pending status with a single hook

jsx
💡 useActionState replaces the old useState dance for form loading + error handling
⚡ The action receives previousState and formData — return any state shape you need
📌 Forms work without JavaScript when paired with server actions — true progressive enhancement
🟢 Use defaultValue (not value) so the form is uncontrolled and works with form data
useActionStateformsreact-19

useOptimistic

Show instant UI feedback while async operations are still in flight

jsx
💡 useOptimistic shows instant feedback then reverts automatically if the action fails
⚡ Must be called inside startTransition or a form action — React enforces this
📌 Add a pending flag in the optimistic state to visually distinguish unsaved items
🟢 No manual rollback needed — React reconciles when the real state updates
useOptimisticoptimistic-uireact-19

useFormStatus & form Actions

Read pending state from a parent form without prop drilling

jsx
💡 useFormStatus reads parent form state — perfect for SubmitButton without prop drilling
⚡ Form actions auto-reset the form after success and provide automatic pending state
📌 useFormStatus only works in CHILD components — wrap your button in its own component
🟢 Combine with useActionState for full form state management without useState
useFormStatusformsreact-19

Server Components

Render components on the server, fetch data directly, and mix with client components

Server Components Basics

Async components that run on the server with direct data access

jsx
💡 Server Components are async, run only on the server, and never ship JS to the browser
⚡ Pass Server Components as children to Client Components — best of both worlds
📌 Props from Server → Client must be serializable: no functions, classes, or Dates
🟢 Default to Server Components and opt into Client Components only when you need interactivity
rscserver-componentsreact-19

Server Actions ('use server')

Call server functions directly from client components and forms

jsx
💡 Server actions look like regular function calls but execute on the server with direct DB access
⚡ Use revalidatePath/revalidateTag to refresh the cached UI after a mutation
📌 Server actions in form action props give progressive enhancement — works without JavaScript
🟢 Always validate inputs in server actions — they are public endpoints accessible to anyone
server-actionsuse-servermutations

Component API Patterns

Patterns for designing flexible and reusable component APIs

Polymorphic Components (as prop)

One component that can render as different elements based on an "as" prop

jsx
💡 The "as" prop pattern keeps semantics flexible while sharing styling and behavior
⚡ Default the "as" prop with a destructure default (as: Component = "div")
📌 Type-safe polymorphism in TypeScript needs ElementType + ComponentPropsWithoutRef
🟢 Used by every major React UI library — Radix, Chakra, Mantine, shadcn/ui
polymorphicas-propapi

Controlled vs Uncontrolled

Two ways to manage component state — let parent control, or manage internally

jsx
💡 Controlled = parent owns state; Uncontrolled = DOM/component owns state
⚡ Building a component to support both is a common library pattern (Radix, MUI)
📌 React warns if you switch between controlled/uncontrolled — pick one and stick with it
🟢 react-hook-form leverages uncontrolled inputs for fewer re-renders on large forms
controlleduncontrolledforms

Provider Pattern with Custom Hooks

Wrap context with a Provider component and a custom hook for safe consumption

jsx
💡 The Provider + custom hook combo is the standard way to expose Context safely
⚡ Throwing in the custom hook gives clear errors when the Provider is missing
📌 Encapsulating state inside the Provider lets you refactor to Zustand/Jotai later without breaking consumers
🟢 Split state and dispatch into separate contexts to prevent unnecessary re-renders
providercontextcustom-hooks