Turtlekit Editorial
React design patterns
React patterns built step by step on real product screens, with the engineering decisions behind each one.
Composition
How components fit together, and who owns the state and the layout.
Single responsibility
One reason to change per component, so a wording fix, an API change and a new action each land in one place.
Presentational and container components
Split how a list looks from what it knows, so the same component serves a server page and a picker dialog.
Children, function children and render props
Elements for what the page knows, functions for what the component knows, so a shared list stops branching.
The variant pattern
A closed set of named variants in place of styling props, so a status looks the same on every screen.
Compound components
Parts that share state through context, so each page arranges the layout while the parent keeps it wired.
Higher-order components
When a function that wraps a component still fits, and how to write one that hides nothing from its callers.
State
Where state should live, and what to compute instead of storing.
State colocation
Keep state in the lowest component that reads it, so typing in one box never re-renders the whole page.
Lifting state up
When two components must agree, move the state to their closest common parent and pass it down as props.
Deriving state during render
Compute what you can from props and state during render, so totals and selections never fall out of step.
One status instead of many booleans
Replace loading, error and success flags with one status value, so impossible combinations can’t render.
Adjusting state when a prop changes
Reset or adjust state when a prop changes without an effect: compute it, key it, or adjust during render.
Reading context with use()
React 19’s use() reads context after an early return or inside a branch, where useContext can’t go.
Context selectors
Let each component subscribe to the slice of shared state it reads, so one busy value doesn’t re-render all.
Hooks, effects and refs
Reusable behaviour, and effects and refs that stay correct as the code changes.
Custom hooks and hook composition
Write shared behaviour once as small hooks that compose, so two screens can’t drift apart while each keeps its own state.
One effect per concern
Give each effect one job and its own dependencies, so typing in a field never reconnects a subscription or logs a view.
The latest ref pattern
Keep the newest value in a ref, so a timer or listener that starts once reads current props without restarting.
useEffectEvent
Read the latest props and state from an effect without restarting it, with React 19.2’s useEffectEvent and its rules.
Detecting the first render
Why a first-render flag breaks in Strict Mode, and the initializer, handler or effect that answers the real question.
useImperativeHandle
Give a parent one small method, such as focus, instead of DOM nodes or a prop to toggle, with React 19’s ref as a prop.
Rendering and performance
Keeping input responsive and pages light, measured before it is optimised.
Debouncing input
Wait for a pause in typing before you search, and cancel the stale request, so a name sends one request.
useDeferredValue
Let the field render first and a slow table catch up in a render React can interrupt, with no delay to tune.
Loading components on demand
Keep code people may never use out of the first download with lazy and Suspense, and fetch it on intent.
Virtualising long lists
Render only the rows in view, keep the scrollbar true, and answer for screen readers and find-in-page.
Loading, empty and error states
The states every screen has besides the happy one, designed rather than left to chance.
Guard clauses and early returns
Return early for each case that ends a render, so the happy path reads flat and TypeScript knows what it holds.
Skeleton placeholders
Hold the space content will take with placeholders in its own shape, so nothing moves when the data arrives.
Rendering the data you have
Let only the data a section can’t do without decide whether it renders, and give every optional part its fallback.
Empty states
Say why a list is empty and offer the next step, and never let a failed load pass for an empty list.
Error boundaries
Keep one section’s crash inside that section, with a fallback that says what still works and keeps focus.
Async data and Actions
Reading async data and changing it, with React 19's Actions, Suspense and optimistic updates.
use() and Suspense
Start the request where the decision is made, read the promise with use(), and let Suspense and a boundary hold the wait and the failure.
useTransition and Actions
Keep the current screen while the next one loads, and let an async Action stay pending until its request settles, with no flags of your own.
Optimistic UI updates
Show an action’s result at once, let React 19 settle it, and roll back with a clear message on failure.
useActionState and form Actions
Let each form submission return the form’s next state, so errors, typed values and the pending state can’t drift apart.
useSyncExternalStore
Read a value React doesn’t own, such as localStorage, so every component shows the same one and other tabs follow.
Focus and the DOM
Reaching real elements: refs, ids, portals and the keyboard paths between them.
Refs in React 19
Pass ref as a plain prop instead of forwardRef, and let a ref callback return its own cleanup, as React 19 allows.
Accessible ids with useId
Tie labels, hints and errors to their fields with ids that are unique on the page and match from server to browser.
Portals
Draw part of a component somewhere else in the DOM while React keeps it where it belongs, and know which tree each rule follows.
Roving focus
Make a toolbar or tab list one Tab stop, with the arrow keys, Home and End moving inside it, mirrored right to left.
Component APIs
What a component hands the people who use it: control of its state, its logic and its markup.
Controlled and uncontrolled components
Decide who owns a component’s value: the parent, through value and onValueChange, or the component itself, from a defaultValue.
State reducer and prop getters
Let the code that uses a hook have the last word on each change and own the markup, while the hook keeps the mechanics.
Headless components and providers
Share behaviour without markup so each screen draws it its own way, and give what is true for a whole account once, from a provider.
The polymorphic as prop
Let a component render the element a call asks for, from a closed list, with the props, events and ref of that element.