React
React is a JavaScript library for building user interfaces out of components, each describing what the screen should show for the current state. React then works out how to change the page to match, and nearly every difficulty with it comes from breaking that model: impure work during render, state kept where it cannot be the source of truth, or an effect doing a job that belonged somewhere else. The page opens with every built-in hook on one screen and the four reasons a component renders, then covers render and commit, re-renders, state as a snapshot, effects, Server Components, and five documented cases.
- Current version
- 19.3 · September 2026
- Model
- UI = f(state)
- Governed by
- React Foundation · 2026
React on one screen: every hook and what it is for
A React component is a function that returns a description of the screen, and hooks are the functions it calls to get anything else — state, a value from higher up the tree, a connection to the outside world. Here is every one of them first, because between them they are almost the whole of what you write in a component. The table lists every built-in hook react.dev documents as of React 19.3 (September 2026), in its groups, with the job each one was made for and the way each one gets misused.
| Hook | What it is for | How it gets misused |
|---|---|---|
| useState | A value that belongs to this component and changes over time | Storing what could be computed from other state or props |
| useReducer | State with several parts that change together, updated by one pure function | A whole application store rebuilt by hand in one component |
| useContext | Reading a value provided higher up without passing it through every level | A value that changes many times a second: every reader re-renders each time |
| useRef | A value that survives renders without causing one — a DOM node, a timer id | Reading or writing it during render, where React cannot see the change |
| useImperativeHandle | Choosing what a parent can call through a ref to your component | An imperative API where an ordinary prop would do |
| useEffect | Keeping the component in sync with a system outside React, after the screen updates | Computing values, or reacting to a click — the effects section below |
| useLayoutEffect | Measuring the page before the browser paints — a tooltip’s position | Anything that does not measure: it holds up the paint |
| useInsertionEffect | CSS-in-JS libraries inserting styles before the DOM changes | Application code — it is not meant for you |
| useEffectEvent | Reading the latest props inside an effect without making the effect re-run (19.2) | Wrapping everything in it to silence the dependency linter |
| useMemo | Keeping an expensive result between renders | Wrapping cheap work, where the comparison costs more than the work |
| useCallback | The same function between renders, for a memoised child or an effect | Every function, by default, as a ritual |
| useTransition | Marking an update as not urgent, so typing stays responsive | Expecting it to make slow code fast — it only reorders the work |
| useDeferredValue | Letting a slow part of the screen lag behind a fast input | A debounce for network requests — it defers rendering, not fetching |
| useActionState | The result of a form action and whether it is still running | A general-purpose reducer for state that has nothing to do with an action |
| useOptimistic | Showing the expected result while an action is still in flight | Forgetting it reverts when the action fails — the failure needs a message |
| use | Reading a promise or a context — the only one allowed inside a condition | A promise created during render: a new one every time, so the component keeps suspending |
| useFormStatus | Whether the form around this component is being submitted (react-dom) | Calling it in the component that renders the <form> — it only sees a form above it |
| useId | A stable id that ties a label to its input, the same on server and client | Keys for a list — keys come from the data |
| useSyncExternalStore | Subscribing to a store React does not own — a library store, a browser API | Wrapping state that could simply have been useState |
| useDebugValue | A label for your own hook in React DevTools | Expensive formatting on every render — pass a formatter instead |
Describe, do not instruct: render and commit
Before React, front-end code mostly gave instructions: find this node, set its text, add a class, remove that row. Every instruction needed a matching one that undid it, and the number of pairs grew faster than the features did — which is why old front-end code bases tended to break in places nobody had touched. React inverts that. You write a function that, given the current state, returns a description of the interface, and React works out the DOMDocument Object Model — the page as a tree of objectsThe tree of objects a browser turns an HTML page into, so that code can read and change it. Change the DOM and the reader sees the change immediately; the HTML file the server sent stays exactly as it was.Full article →All terms operations needed to match it. You never remove the row; you describe a list that no longer contains it. There is one description to get right instead of a growing set of transitions between states.
The diagram splits the work into two phases, and the split is the most load-bearing idea on this page. The render phase calls your components to produce the description. It must be pure — the same inputs give the same output, and nothing outside the function changes — because React may run it twice, pause it halfway, or throw the result away. The commit phase applies the difference to the real DOM, once. Effects run after the commit, when the page is already up to date.
When a component re-renders
The four reasons from the top of the page produce one pattern in practice. When state changes in a component, that component renders, and so does everything below it, all the way down — whether or not the children receive anything that changed. Nothing above it renders. That is a deliberate default: calling a function and comparing its output is cheap, and a re-render is not a DOM update. It becomes expensive only when the subtree is large or a component in it does heavy work during render.
The diagram shows the three ways out, and they are worth trying in this order, because the first two are free and the third has a price. First, move the state down: if only one small subtree cares about a value, keep the state there and the rest of the page stops rendering. Second, pass pieces of the screen in as children: an element created by a parent that did not re-render is the same element as last time, and React skips it. Only then reach for memo, useMemo and useCallback. Each adds a comparison to every render, and each pays off only when the work it skips is genuinely larger than that comparison.
Since October 2025 a fourth option exists that changes the arithmetic. React Compiler 1.0 is a build step that reads your components and inserts the memoisation itself, more precisely than people write it by hand — it can memoise after an early return, which a hand-written useMemo cannot. At Meta it made initial loads and navigations in the Quest Store up to 12% faster and some interactions more than two and a half times faster. It has one condition: your code must follow the rules of React, render purity first among them. The compiler does not fix a component that breaks them; it skips it, and its lint rules tell you where.
Keys are identity, not decoration
One correctness rule hides inside the performance topic. When React renders a list, it uses each item’s key to decide which element on this render is the same as which element on the last one — and state, focus and the text half-typed into an input all belong to that identity. Using the array index as the key tells React that “the item in position two is the same item as before”, which stops being true the moment the list is sorted or an item is removed from the middle. The visible result is a text field or a checkbox that stays where it was while the data moves under it. Use a stable id from the data.
State: a snapshot, a queue and one source of truth
Inside one render, state does not change. count is a constant for the whole of that call to your function, and calling setCount does not touch it: it puts an update in a queue and asks React for another render. That is why three setCount(count + 1) calls in one click leave the counter at one, not three — each of them read the same count, which was zero, and each asked for one. Passing a function instead, setCount(c => c + 1), queues three steps that each receive the result of the one before.
Since React 18 the queue is also batched everywhere: every update made during one event — in a handler, a timeout or after an await — is applied in a single render rather than one render each. And a queued value only causes a render if React considers it different, which it checks with Object.is: the same reference counts as unchanged. So pushing into an array that is already in state, or setting a field on an object that is already in state, hands React the same address and nothing happens on screen. The JavaScript page draws what a copy actually copies; for state, build a new object for every level you change.
The other half of state design is what deserves to be state at all. Anything you can compute from existing state or props during render should be computed, not stored. A fullName kept in state beside firstName and lastName is a third value that can disagree with the other two, and eventually will. The test is blunt: if two pieces of state can ever contradict each other, one of them is derived and should be deleted. Facebook’s chat team learned it the hard way and described it in 2014, with an unread count that kept showing messages nobody had sent — the first case below.
| Kind of state | Example | Where it belongs |
|---|---|---|
| Local UI state | An open menu, the selected tab | useState in the lowest component that needs it |
| Derived value | A filtered list, a total, a full name | Nowhere — compute it during render |
| Shared UI state | The theme, the signed-in user | Lifted to the nearest common parent, or a context if it changes rarely |
| Server data | The list of orders, the product page | A data library or the framework’s loader — it is a cache, not your state |
| URL state | The search query, the page number, a filter | The URL, through the router — so it survives a reload and a shared link |
Effects synchronise with the outside world
useEffect exists to keep a component in sync with something outside React: a subscription, a browser APIApplication Programming Interface — contract between programsThe rules one program follows to call another: which requests it may send, in what shape, and what comes back. To the caller it is a contract — everything behind it stays a black box, which is exactly what lets the other side be rewritten without breaking you.Full article →All terms, a chart library that owns its own DOM node, a timer. That is its whole job. React’s own documentation has a page called “You Might Not Need an Effect”, which says a good deal about how often it is reached for by default. Most effects in a typical code base belong in one of the places on the right of this table.
| You wrote an effect to… | Do this instead |
|---|---|
| Compute a value when props change | Compute it during render. If it is genuinely expensive, useMemo — but measure first. |
| Reset state when a prop changes | Give the component a key. A new key is a new component with fresh state, and it takes no code. |
| Send a request when a button is clicked | Do it in the event handler. The cause is the click, not the render. |
| Tell a parent that state changed | Call the callback where the change happens, or lift the state so there is nothing to tell. |
| Subscribe to a store or a browser API | useSyncExternalStore, which handles subscribing, unsubscribing and consistency for you. |
| Fetch data when the screen opens | A legitimate use, but prefer a data library or the framework’s loader — a bare effect has no cache and no cancellation, and it races. |
When an effect is right, two parts of it need care. The first is the dependency array — the list of values that makes the effect run again when one of them changes. React compares each entry with Object.is, so an object or a function created during render is a new value every time, and an effect that depends on it runs after every single render. On a screen that renders often, an effect that calls an API becomes a loop that calls it constantly. That is exactly what took down Cloudflare’s dashboard in September 2025. Depend on primitive values — an id rather than the object that holds it — or keep the object stable with useMemo.
The second is the cleanup function, which is not optional. It runs before the effect runs again and when the component disappears, and it is where you unsubscribe, clear the timer and abort the request. An effect that subscribes without unsubscribing leaks a listener on every run — invisible in development, and the reason the tab is slow after twenty minutes. An effect that fetches without cleanup has a race conditiona bug that depends on timingA bug that appears only on a particular coincidence in time: two threads or two requests read and change the same thing, and the result depends on who got there first. It reproduces badly, which is why it is usually found last and in production.All terms that your development machine rarely shows you:
Where React runs now: frameworks and Server Components
For most of its life React was something you set up yourself, and Create React App was the standard way to start. In February 2025 the React team retired it and began recommending frameworks — Next.js, React Router, Expo for mobile — or a plain build tool such as Vitea front-end build toolA build tool and development server for front-end code, started in 2020 by Vue’s author and now used with most frameworks. In development it serves your source files to the browser almost as they are, so it starts in a moment; for production it bundles and minifies them.All terms for those who want to assemble the rest themselves. React is still a library, and that is a real trade rather than a slogan: routing, data loading, forms and the build are decisions you make and then own, and two React code bases in the same company can share almost no conventions. A framework makes those decisions for you, and brings one more with it: some of your components now run on a server.
| Server Component | Client Component | Server Function | |
|---|---|---|---|
| Marked with | Nothing — the default in a framework | 'use client' at the top of the file | 'use server' |
| Runs | On the server, before the page is sent | On the server for the first HTML, then in the browser | On the server, when the browser calls it |
| Can | Read a database or a file directly | Hold state, run effects, handle clicks | Change data on the server from a form or a button |
| Ships code to the browser | None | All of it | None — but it is a public endpoint |
The gain from Server Components is mostly a bundle-size argument. A date-formatting library used only on the server costs the user nothing, and data loading moves next to the component that needs it, without a separate API in between. The line to hold is that anything interactive — onClick, state, an effect — lives in a Client Component, so the useful shape is a server tree with small client leaves. It is the shape this encyclopedia is built in: every article you read here is rendered by Server Components, and only small leaves — the menu, the search box, the table of contents, the table headers that stay put while you scroll — are Client Components.
Running on the server has a second cost: the server now runs React’s code for turning a request back into data, and that code can have bugs like any other. In December 2025 it had one rated 10 out of 10 — React2Shell, the fifth case below. And there is a seam where the two halves meet. The HTML the server sends must match what the browser renders when React takes the page over, a step called hydration; anything that differs between the two — the current time, a random number, the visitor’s time zone — produces a mismatch warning or a flicker. Put such values in an effect, or, since 19.3, behind browser(), so the server does not guess them.
Five cases, and what each one was missing
Each case below was described in public by the company it happened to, or by the React team. Three of them are about the model this page describes, and two are about what surrounds it — the licence and the server.
| Case | What happened | What was missing |
|---|---|---|
| Facebook chat, 2014 | The unread count showed messages that did not exist, and came back after every fix | One source of truth, and data that flows one way |
| BSD+Patents, 2017 | Apache banned the licence and WordPress planned to leave; React moved to MIT within weeks | A licence its users’ lawyers could accept |
| Create React App, 2025 | The standard starter for most React apps was retired with no maintainers left | An owner for the setup everyone copied |
| Cloudflare, Sep 2025 | A dashboard effect re-ran on every render and overloaded the service that authorises every API call | A stable dependency, and retries with random delays |
| React2Shell, Dec 2025 | A flaw in how Server Components read requests let anyone run code on the server | Knowing where React runs on a server, and a patch path measured in hours |
The first case is where React’s way of thinking about state comes from. Facebook’s chat showed the number of unread messages in more than one place on the page, and each of those views kept and updated its own idea of what was unread. The count kept showing messages that did not exist. Engineers fixed it, and it came back with the next feature that touched chat, because any view could update any other and nobody could hold all the paths in their head. Jing Chen presented the answer at F8 in 2014: data flows in one direction, from a single store to every view, and a view changes the data only by sending an action back to the start. That is Flux, and it is the same rule as “if two pieces of state can contradict each other, one of them is derived”.
The second is a reminder that a library is also a legal agreement. React was published under a BSD licence with an extra patent clause: the grant ended for anyone who sued Facebook over patents. In July 2017 the Apache Software Foundation put that licence on its list of licences its projects may not depend on, and in September Matt Mullenweg announced that WordPress would move its new editor off React. On 22 September Facebook relicensed React under MIT, and React 16 shipped under it four days later. The code had not changed at all. What had been missing was a licence that the lawyers of the companies using it could sign off.
Where it degrades
A React code base rarely breaks in a way a test would catch. It gets slower, it shows a stale value for a moment, it renders twice for reasons nobody can name, and its effects slowly turn into a second program that runs beside the first. These are the shapes that takes.
- Derived values stored in state, which can disagree with the values they were derived from.
- Effects used to keep two pieces of state in sync — a calculation written a frame late.
- An object or a function in a dependency array, so the effect runs after every render.
- Fetching in a bare effect with no cleanup, which races and leaks.
- The array index as a key, which attaches state and focus to the wrong row after a reorder.
- Memoising everything by default, which adds a comparison to every render and hides the real cost.
- Changing state in place, so React sees the same reference and skips the update.
- Everything in one global store, which turns every change into an application-wide event.
- Server Functions written as if only your own buttons could call them.
There is also an honest limit, and it is built into the one-line model at the top of the page. React guarantees that the screen matches the state. It says nothing about whether the state is right, whether the network answered, or whether the thing on the screen can be used. A <div onClick> rendered by the best-structured component tree in the world is still invisible to a keyboard and a screen reader, which the HTML and CSS page covers from the other side. And the library cannot make the page light: every Client Component is JavaScript the phone has to download, parse and run before the first click works.
The practical check is the same one that works for any UIUser Interface — what the user seesEverything the user sees and operates: screens, buttons, fields, states. UI is how the interaction looks; whether the interaction makes sense in the first place is a UX question, and the two get confused constantly.All terms code. Open the React DevTools profiler, turn on “highlight updates”, and do the one thing the screen exists for: every flash that is not the part you touched is a re-render you can name with the four reasons. Then do it again on a mid-range phone. The first test finds wasted work. The second finds whether anybody feels it.
When to use it
Use it when
- The interface has genuine state that changes over time and in several places at once.
- You want a component model and will take a framework, or choose routing, data and build tooling yourself.
- The hiring pool matters — it is the largest one on the front end.
- Server Components can move data loading and heavy libraries off the phone.
Avoid it when
- A content page with a little interactivity — HTML with a small script is smaller and faster.
- The team wants conventions supplied rather than chosen — that is what Angular offers instead.
- Server Components on a team with no process for patching a server dependency the same day.
- Adding it for one widget on an otherwise server-rendered page, where the runtime outweighs the widget.
Sources and method
What this page stands on
- 12 sources
- 2 documented failures
- Checked October 13, 2026
Practices and where the terms come from
every hook, the four reasons a component renders, and the versions- DocumentationBuilt-in React Hooks (opens in a new tab)react.dev
- DocumentationYou Might Not Need an Effect (opens in a new tab)react.dev
- DocumentationQueueing a Series of State Updates (opens in a new tab)react.dev
- ArticleReact v19 (opens in a new tab)React Blog · Dec 5, 2024
- ArticleReact 19.2 (opens in a new tab)React Blog · Oct 1, 2025
- ArticleReact Compiler v1.0 (opens in a new tab)React Blog · Oct 7, 2025
- ArticleSunsetting Create React App (opens in a new tab)React Blog · Feb 14, 2025
The failures this page learns from
Cloudflare’s outage and React2Shell, in “Five cases”Flux and the licence
the other cases: Facebook chat’s unread count and BSD+PatentsResearched with Claude. Finding and cross-checking the primary sources was done with Claude (Anthropic). Selection, writing and fact-checking: the Anatomy of IT Product editors.
Found this useful?
Share it with someone who is working on the same problem.