The memorizable facts, condensed. Everything here is original material summarizing the
official documentation —
verify details against it before relying on them in production.
Core hooks, one rule each
Rules of hooks: call them only at the top level of a component or custom hook — never in loops, conditions, or handlers. The one exception is use(), which may be called conditionally.
| Hook | One-line rule |
useState | Returns [value, setter]; the setter enqueues a re-render, and each render sees a fixed snapshot of state. |
useReducer | Dispatch plain action objects to a pure reducer when the next state depends on the last or spans several fields. |
useEffect | Synchronize with an external system after commit; the cleanup runs before every re-run and on unmount. |
useLayoutEffect | Fires synchronously after DOM mutations but before paint — reserve it for reading layout. |
useRef | A mutable .current box that survives renders and never triggers one when it changes. |
useContext | Reads the nearest provider's value and re-renders the component whenever that value changes. |
useMemo | Caches a computed value between renders until a dependency changes. |
useCallback | Caches a function's identity; useCallback(fn, deps) is exactly useMemo(() => fn, deps). |
useTransition | Marks updates as non-urgent so urgent input stays responsive; returns [isPending, startTransition]. |
useDeferredValue | Lets a value lag behind urgent updates — a built-in debounce driven by rendering priority. |
useSyncExternalStore | The safe subscription to an external store; takes subscribe and getSnapshot and avoids tearing. |
useId | Generates hydration-safe unique ids for accessibility attributes — never use it for list keys. |
useImperativeHandle | Customizes the object a parent receives through a ref instead of exposing the raw DOM node. |
What triggers a re-render (and what does not)
| Cause | Effect |
setState | Queues a re-render — unless the new value is Object.is-equal to the current one, which bails out. |
parent render | Re-renders every child by default, whether or not any prop changed. |
context change | Re-renders every consumer of that context, memoized or not. |
dispatch | A useReducer dispatch re-renders exactly like setState, with the same Object.is bailout. |
prop change | Never happens alone — props only change because the parent rendered, and that render is the actual trigger. |
ref.current = | Never triggers a render; refs are invisible to the render cycle. |
state mutation | Mutating an object held in state triggers nothing — React only reacts to the setter being called with a new reference. |
batching | Since React 18 all updates in one tick batch into a single render, including timeouts, promises, and native handlers. |
StrictMode | Double-invokes render and remounts effects once, in development only, to surface impure code. |
React 19 cheat table
Shipped December 2024; the React Compiler went stable in 2025. These are the answers interviewers now expect instead of the React 18 ones.
| Change | What to say |
ref as prop | Function components receive ref as a regular prop, so forwardRef is no longer needed and is deprecated. |
Actions | Async functions run in a transition that give you pending state, error handling, and optimistic updates for free. |
useActionState | Wraps an action into [state, formAction, isPending]; it replaces react-dom's useFormState. |
useOptimistic | Shows a temporary optimistic value while an action is in flight, then settles to the real result. |
use() | Reads a promise or a context during render, and unlike other hooks it may be called conditionally. |
form actions | Passing a function to <form action> hands it FormData and resets uncontrolled fields after a successful submit. |
useFormStatus | Reads the enclosing form's pending state from a child component, like context for the nearest <form>. |
<Context> | A context object now renders directly as its own provider; <Context.Provider> is deprecated. |
ref cleanup | Ref callbacks may return a cleanup function, replacing the old call-with-null pattern. |
metadata | <title>, <meta>, and <link> rendered anywhere in the tree are hoisted into the document head. |
removed | propTypes, defaultProps on function components, string refs, legacy context, and ReactDOM.render/hydrate/findDOMNode are gone. |
Compiler | The React Compiler auto-memoizes components at build time, making most manual memoization unnecessary. |
Server Components: boundary rules
| Rule | Detail |
default | In an RSC framework every component is a Server Component until a 'use client' boundary says otherwise. |
'use client' | Marks the file — and everything it imports — as client bundle; it is a boundary directive, not a per-component flag. |
'use server' | Marks Server Functions callable from the client; it does not create Server Components. |
server limits | Server Components cannot use state, effects, event handlers, or browser APIs — they render once on the server. |
client limits | Client components cannot import Server Components, but can receive them as children or other props. |
serialization | Boundary props must serialize: primitives, plain objects, arrays, Date, Map/Set, promises, JSX, and Server Functions pass; class instances and other functions do not. |
async | Server Components may be async and await data directly; the client unwraps a passed promise with use(). |
Memoization: which tool when
| Tool | Use it when |
memo() | Wraps a component so it skips re-rendering when a shallow compare finds its props unchanged. |
useMemo | Caches a genuinely expensive computation, or an object identity that feeds memoized children or dependency arrays. |
useCallback | Keeps a function's identity stable for a memoized child or an effect dependency — never for its own sake. |
fresh literals | An inline object or arrow prop defeats memo() on every render; memoize the value or hoist it out of the component. |
context value | Memoize a provider's value object, or every consumer re-renders each time the provider does. |
Compiler | With the React Compiler enabled, hand-written memo/useMemo/useCallback are mostly redundant — let it do the work. |
default | Don't memoize by reflex — memoization has its own cost, so profile before adding it. |
Testing Library: query priority
Priority mirrors how users find things: accessible role first, test ids as the last resort.
| Query | Rule |
getByRole | The first choice — queries the accessibility tree, usually with { name } to match the accessible name. |
getByLabelText | The go-to for form fields, matching the way users read a form. |
getByPlaceholderText | Acceptable only when there is no label — a placeholder is not a label substitute. |
getByText | Finds non-interactive elements by their visible text. |
getByDisplayValue | Matches a form element by its current filled-in value. |
getByAltText | For images; like getByTitle it sits low on the list because users rarely see the attribute. |
getByTestId | The escape hatch when nothing user-facing can match. |
queryBy* | Returns null instead of throwing, so it exists mainly to assert an element is absent. |
findBy* | getBy* wrapped in waitFor — returns a promise and retries until the element appears (1 s default timeout). |
waitFor | Retries any assertion until it passes; use waitForElementToBeRemoved for disappearance. |
userEvent | Prefer userEvent.setup() over fireEvent — it simulates full browser interactions, not single dispatched events. |
Keys, lists, and their warnings
| Rule | Why |
stable + unique | A key must be stable across renders and unique among siblings — usually the data's own id. |
index as key | Breaks the moment the list reorders, inserts, or deletes — state and DOM stick to the wrong items. |
key change | Changing a key unmounts and remounts the component, which is also the idiomatic way to force a state reset. |
not a prop | key never reaches the component as a prop; pass the same value under another name if the child needs it. |
fragments | The <>...</> shorthand cannot take a key — spell out <Fragment key={...}> in mapped lists. |
the warning | 'Each child in a list should have a unique key' means the key belongs on the outermost element returned by map(). |
no globals | Keys need only be unique among siblings, never globally — and never generate them during render (no Math.random()). |
Independent community study resource — not affiliated with or endorsed by Meta Platforms, Inc. React is a trademark of Meta Platforms, Inc. All questions and study notes are original, written from the official React documentation. Everything runs in your browser; nothing you answer is stored or transmitted.