LearnThatStack Ace your next interview

React

React 19 with function components and Hooks Checked Sep 2026 91 code snippets

The model

  • A component is a function that turns props and state into elements. When either changes, React calls it again and gets new elements.
  • Each render is a snapshot. Its props, state and handlers stay fixed, so a callback that outlives the render still reads the old values.
  • React diffs the new element tree with the last one and writes only the changes to the DOM. React calls this reconciliation, and key tells it which list item is which.
  • Rendering must be pure. Fetching, subscribing and timers go in event handlers or useEffect, never in the component body.
  • Data flows down as props, and a child reports back by calling a function prop. State that two components share lives in their closest common parent.
Your componenta functionReactvirtual DOMReal DOMbrowser nodesScreenwhat users seeTRIGGERsetCount(1)RENDERcalls it againnew elements diffedCOMMITonly the changesuseLayoutEffectPAINTpaintuseEffect
Read top to bottom. React re-runs your component and writes only what changed. useLayoutEffect runs before paint, and useEffect usually after.

Components & JSX

what a component is and how JSX works

Function and class components

Write a componentconst Hi = ({ name }) => <p>{name}</p>;
Write one as a classclass Hi extends React.ComponentReturn JSX from its render method.
Tell an element from a componentAn element describes UI. A component returns elements.

TipHooks give function components state and effects, so new code uses functions. Only error boundaries still need a class.

TrapStart the name with a capital letter. JSX reads <hello /> as an HTML tag.

How React updates the page

Say what the virtual DOM isAn in-memory copy of the UI that React diffs.
Name React's engine (16+)Fiber. It can pause a render, then commits in one pass.
Mount the appconst root = createRoot(el);root.render(<App />);
Mount it the old wayReactDOM.render(<App />, el)Removed in React 19.

Tipreact defines components and Hooks. react-dom renders them into the browser DOM.

Lists and conditions

ANewA
key={item.id}Insert New at the top. The key matches A to its old row, so A keeps its state.
0: A0: New1: A
key={index}Rows match by position, so New gets A's state and A starts empty.
Render a listtodos.map(t => <Todo key={t.id} {...t} />)
Show one of two elements{isLoggedIn ? <Home /> : <Login />}
Reset a child's state<Form key={userId} />

Trap{count && <List />} shows 0 when count is 0. Make the left side a boolean.

Props, state & events

data in, data owned, and user input

State with useState

Give a component its own stateconst [count, setCount] = useState(0);
Update from the previous valuesetCount(c => c + 1)
Update an object without mutating itsetUser({ ...user, name })
Tell props from stateProps are read-only inputs. State is the component's own memory.

TipNever mutate state. React re-renders only when you call the setter with a new value.

TrapCalling setCount(count + 1) twice in one handler adds 1, not 2. Both calls read the same count.

Hooks & effects

effects, refs and the rules

When an effect runs

useEffect(fn)Run after every render
useEffect(fn, [])Run once, after mount
useEffect(fn, [id])Run again when id changes
the effect runsReact skips it

TipReact compares each dependency with Object.is. A new object or function every render counts as a change.

TrapStrict Mode runs setup and cleanup one extra time in development, so even a [] effect runs twice.

Fetch data in an effect

Catch a failed requestWrap the await in try and catch, and keep the error in state.
Ignore a response that arrives too lateSet an ignore flag in the cleanup, and skip the state update.

TipError boundaries don't catch errors in async code, so the effect must catch them.

Trapfetch rejects only on a network failure. Check res.ok, or a 500 looks like success.

Fix a stale closure

Re-run the effect with fresh valuesAdd the value to the deps. The cleanup clears the old timer.
Read fresh values without re-running (19.2+)useEffectEvent(fn)Before 19.2, use a ref.

TrapAn interval set in an [] effect reads state from the first render forever. Use the updater setCount(c => c + 1) instead.

Refs

Focus an inputuseRef(null)ref.current.focus()
Take a ref as a propfunction Input({ ref })
Do the same before React 19forwardRef((props, ref) => <input ref={ref} />)

TrapChanging ref.current doesn't re-render. Keep anything the screen shows in state.

Context & global state

share data across the tree

Context

Provide a value to everything below<UserContext.Provider value={user}>
Provide it in React 19<UserContext value={user}>
Read it in any childuseContext(UserContext)
Keep the value object stableuseMemo(() => ({ user, login }), [user])

TipWrap it in a useUser Hook that throws a clear error outside the provider.

TrapEvery reader re-renders when the value changes, even inside memo. Split fast and slow values into separate contexts.

Pick a state tool

Share state that changes oftenRedux Toolkit or Zustand.
Cache data from the serverTanStack Query or SWR.
Keep state across a page refreshlocalStorageRead it back in a lazy useState initializer.
Subscribe to a store outside ReactuseSyncExternalStorePass it subscribe and getSnapshot.

TipStart with useState, useReducer and Context. In a small app a library only adds setup.

Redux

Create the storeconfigureStore({ reducer })
Create it the old waycreateStore(reducer)Deprecated.
Read state and dispatch actionsuseSelector(s => s.count)useDispatch()

TipRedux keeps one store with read-only state. Only a dispatched action changes it, through a pure reducer.

Performance

render less, load less, and measure first

Skip re-renders

Memoize a componentmemo(Row)
Keep a handler the same across rendersuseCallback(() => save(id), [id])
Tell memo from useMemomemo wraps a component. useMemo caches a value.

TipuseCallback(fn, deps) equals useMemo(() => fn, deps). It helps only with a memo child or a Hook that depends on it.

TrapA new inline object or function each render breaks memo. The child re-renders anyway.

useMemo and the React Compiler

Cache a slow calculationuseMemo(() => sort(list), [list])
Decide when to memoizeWhen the work is slow, or the result is a prop or a dependency.
Let the build memoize for youReact Compiler memoizes at build time. 1.0 shipped in October 2025.

TipMeasure first. Memoizing cheap work only adds overhead.

Big bundles and long lists

Load a component's code on first renderlazy(() => import('./Chart'))
Show a fallback while it loads<Suspense fallback={<Spinner />}>
Lazy-load imagesloading="lazy"
Render only the rows on screenreact-windowIts List renders only the visible rows.
Load the next page at the end of the listIntersectionObserverWatch the last item, and fetch when it appears.

TrapDeclare lazy components at the top of a module. Inside a component, their state resets on every render.

Forms & inputs

controlled inputs, many fields and validation

Controlled or uncontrolled

Keep an input's value in state<input value={v} onChange={onChange} />
Let the DOM hold the value<input defaultValue="" ref={ref} />
Stop a submit from reloading the pagee.preventDefault()Call it in onSubmit.
Link a label to its inputconst id = useId();Use it in htmlFor and id.

TipControlled inputs suit checking as you type. Uncontrolled ones suit simple forms and file inputs.

TrapReturning false doesn't stop a submit in React. Call preventDefault().

React 18, 19 & SSR

new Hooks and server rendering

Concurrent rendering

Mark an update as non-urgentstartTransition(() => setList(l))
Defer a slow listuseDeferredValue(query)
Name what React 18 addedConcurrent rendering, automatic batching, streaming SSR and useId.

TipUse useTransition when you own the setter, and useDeferredValue when you only receive the value.

TrapuseDeferredValue gains nothing unless the slow component is wrapped in memo.

What React 19 added

Run a form action and track its resultuseActionState(action, init)
Show a change before the server confirms ituseOptimistic(todos, addTodo)
Read a promise in renderuse(promise)

TipuseOptimistic shows the confirmed state again when the action ends, so a failed request reverts itself.

TrapReact 19 removed ReactDOM.render, string refs and findDOMNode, and it requires the new JSX transform.

Render on the server

Send finished HTML for each requestSSR. Fast first paint and good SEO, but more server work.
Build pages once and serve them from a CDNSSG. Content changes only on a rebuild.
Make server HTML interactivehydrateRoot(rootEl, <App />)
Keep a component's code out of the browserA Server Component. It can read the database, but has no state.

TipStart a file with 'use client' to make its components Client Components, with state and events.

TrapClient and server must render the same HTML. The time or typeof window in render breaks that.

Component patterns

reuse markup and logic across components

Composition and portals

Wrap any content in a generic box{children}
Split data fetching from renderingA container fetches and holds state. A presentational component only renders props.
Render a modal outside the parent's DOMcreatePortal(children, modalRoot)

TrapA portal's events bubble through its React parents, not its DOM parents. It still reads their context too.

HOCs, render props and compound components

Wrap a component to add behaviourwithAuth(Panel)
Let the caller decide what to render<Mouse render={pos => <Dot {...pos} />} />
Do it with a HookuseAuth()
Build parts that work as one, like selectThe parts read the parent's state through context.
Let callers change how a Hook updates stateuseToggle({ reducer })

TrapStacked HOCs can clash on prop names and bury the tree in DevTools.

Undo, drag and drop, event bus

Add undo and redoA history array and an index. A new edit drops everything after it.
Let a drag target accept a droponDragOver={e => e.preventDefault()}
Notify components that share no parentSubscribe in useEffect, and return the unsubscribe.

TrapKeep the history and index in one state object, and change it with an updater.

Routing & auth

pages, URL data, guarded routes and XSS

React Router

Map a path to a component<Route path="/users/:id" element={<User />} />
Read :id from the pathconst { id } = useParams();
Read the query stringuseSearchParams()
Route on a host you can't configure<HashRouter>URLs look like /#/about.

TipParams are always strings. Convert numbers yourself, and handle a missing one.

TrapWith BrowserRouter, a refresh on /about asks the server for /about. It must return index.html.

Protect routes and users

Send signed-out users to the login page<Navigate to="/login" replace />
Store the sessionIn an httpOnly cookie. Scripts can't read it, so XSS can't steal it.
Clean user HTML before you render itDOMPurify.sanitize(raw)
Limit where scripts can load fromContent-Security-Policy: script-src 'self'

TipReact escapes text in {}. Only dangerouslySetInnerHTML inserts raw HTML.

TrapA client-side guard only hides screens. The server must check every API request.

Test, build & deploy

tests, builds and hosting

Start, configure and deploy

Start a new appnpm create vite@latest my-app -- --template react
Start one with Create React AppDeprecated. Use Vite, or a framework like Next.js.
Read an environment variableimport.meta.env
Serve client routes after a refreshtry_files $uri $uri/ /index.html;

TipVite exposes only VITE_ variables to your code, as strings. Compare a flag with 'true'.

TrapEnv values end up in the bundle as plain text. Never put secrets in them.

Found this useful? Pass it on.
Pro · $10/mo

This sheet stays free. With Pro, you can:

  • Every answer on this sheet. Read the full answer to all 103 questions it links, not just the 15 free ones.
  • My sheet. The cards you star and the ones you miss in Quiz me, from every sheet, on one page to quiz and print.
  • PDFs. Download this sheet and My sheet, laid out for A4, with every question a link to its answer.
  • The rest of Pro. Every answer in the question library, and 1,000 AI credits a month.