What will happen when this code runs?
useEffect without a dependency array runs after every render. Setting state inside it triggers another render, which triggers the effect again - causing an infinite loop.
Master 100 concepts with detailed explanations.
useEffect without a dependency array runs after every render. Setting state inside it triggers another render, which triggers the effect again - causing an infinite loop.
useMemo memoizes the result of a computation. useCallback memoizes a function reference. useMemo is the right choice when you want to cache a derived value rather than a function.
Keys help React's reconciler match elements between renders. Without stable keys, React may re-create DOM nodes unnecessarily or produce incorrect diffs.
useState(5) initialises the state to 5. On the initial render the value of n is 5, so the button shows 5. The functional updater form n => n + 1 is only called when the button is clicked.
React 18 introduced automatic batching, which batches state updates from all sources (event handlers, timeouts, Promises, native event listeners) into a single re-render. Prior to React 18, batching only happened in React-controlled event handlers.
StrictMode intentionally double-invokes render methods, state initializers, and effects (in development only) to surface side-effects that should be pure. It has no effect in production.
useCallback(fn, deps) returns a memoized function that only changes if one of the deps changes. It is useful when passing callbacks to child components that are wrapped in React.memo to prevent unnecessary re-renders.
React state must be treated as immutable. The correct approach is to spread the outer object and spread the nested object with the updated field. Options A, C, and D mutate the existing state reference, which React may not detect as a change.
useRef returns a mutable object { current: initialValue }. Mutating .current does not cause a re-render, making it useful for DOM references and persisting mutable values across renders without causing updates.
In a controlled component, form data is handled by React state via value + onChange. In an uncontrolled component, form data is handled by the DOM itself and you read it with a ref when needed.
State updates are asynchronous. All three setX(x + 1) calls read the same stale closure value of x (0), so they all schedule a single update to 1. The console.log runs synchronously and still sees 0. The button re-renders showing 1.
React.memo is a higher-order component that performs a shallow comparison of props. If props are equal to the previous render, React skips the render and reuses the last rendered output.
useLayoutEffect fires synchronously after all DOM mutations but before the browser has a chance to paint. This is useful for reading layout or synchronously re-styling the DOM to prevent a visual flicker. useEffect, by contrast, runs after the paint.
React Context provides a way to share values (theme, locale, auth user, etc.) between components at any depth without manually passing them as props through every intermediate component.
The dependency array tells React when to re-run the effect. An empty array [] means run once on mount. No array means run after every render. A populated array means run when any listed dependency changes between renders.
useReducer initializes state to { count: 0 }. Dispatching { type: 'inc' } calls the reducer, which returns a new state object with count incremented by 1. React re-renders the component with the updated state.
When you use the functional updater form (c => c + 1), each call receives the most recently queued state, not the stale closure value. Three successive functional updaters each add 1, so count goes from 0 to 3.
React relies on the order of hook calls staying the same between renders. Calling hooks conditionally or inside loops can break this order. The eslint-plugin-react-hooks enforces this rule automatically.
React used a synthetic event pool in versions before React 17. After the event handler returned, the event was recycled and all properties nullified. React 17 removed event pooling, so this is no longer an issue in modern React.
React.lazy() accepts a function that calls a dynamic import() and returns a Promise. Combined with Suspense, it lets React load that component's bundle on demand, reducing the initial bundle size.
The component body (and its console.log('render')) executes first during rendering. After React commits to the DOM, useEffect runs and logs 'effect'. The cleanup function runs when the component unmounts, not on mount.
ReactDOM.createPortal(children, domNode) renders children into a different DOM node, typically document.body, while keeping them in the React tree. This is commonly used for modals and tooltips that need to escape overflow:hidden containers.
React.forwardRef((props, ref) => ...) gives the component access to the ref passed by its parent. You attach that ref to the DOM element (or child component) you want to expose. Without forwardRef, the ref prop is not forwarded.
In React 18 StrictMode (development only), effects are intentionally mounted, unmounted, then mounted again to help surface bugs from missing cleanup. You will see 'mount', 'unmount', 'mount' in the console.
useTransition() returns [isPending, startTransition]. Wrapping a state update in startTransition marks it as non-urgent, letting React keep the UI responsive. isPending is true while the transition is in progress.
useDeferredValue(value) returns a version of the value that React can defer updating during urgent renders. It lets you keep the UI responsive by rendering the expensive part (like a filtered list) with a slightly stale value.
On the first render, useRef() initializes to undefined (no initial value given). The effect that sets ref.current = value runs after the render, so the return value on first render is undefined. On subsequent renders it returns the previous value.
createContext should be called at module level (outside components). The Provider wraps the subtree and provides a value. Any descendant can call useContext(Ctx) to subscribe to that value and re-render when it changes.
React requires a single root element, but sometimes adding a wrapper div pollutes the DOM. <React.Fragment> (or the shorthand <>) groups multiple children without adding any real DOM node.
A component re-renders when its own state changes, when its parent re-renders (unless blocked by React.memo), or when a context value it subscribes to changes. All three triggers can independently cause a re-render.
In JSX, false, null, and undefined render nothing. However, the number 0 is a valid React child and does render as the character '0'. This is a common bug when writing {array.length && <Component />} - it renders 0 when the array is empty.
Prop drilling happens when you pass data through many intermediate components that don't need it themselves. React Context (or external state managers like Zustand or Redux) solves this by making data available to any component in the tree.
When items are reordered or removed, the index of each item changes. React matches old and new elements by key, so it may reuse the wrong DOM node or component state, causing subtle bugs like incorrect input values.
Error boundaries catch JavaScript errors during rendering, in lifecycle methods, and in constructors of the whole child tree. They do not catch errors in event handlers, async code, server-side rendering, or errors thrown inside the error boundary itself.
static getDerivedStateFromError(error) updates state so the next render shows a fallback UI. componentDidCatch(error, info) is for logging the error. Together they form a complete error boundary. Function components cannot be error boundaries yet.
Props flow down from parent to child and are read-only inside the receiving component. State is local, mutable data that the component manages itself. Changing state schedules a re-render; mutating props directly is forbidden.
useImperativeHandle(ref, () => ({ method })) customizes the value that the parent sees when it holds a ref to the child component. It is always paired with forwardRef and lets you expose a controlled API instead of the raw DOM node.
A custom hook is any function whose name starts with 'use' and that calls React hooks inside it. Option B is an arrow function starting with 'use' that uses useState, making it a valid custom hook. Option A does not start with 'use'.
The default value passed to createContext is only used when a component does not have a matching Provider above it. Because Child is wrapped by <ThemeContext.Provider value='dark'>, useContext returns 'dark'.
React.Suspense wraps components that may need to wait (for lazy imports or data fetching via Suspense-compatible libraries). While waiting, React renders the fallback prop. When the component is ready, React replaces the fallback with the real UI.
Passing a function (lazy initializer) to useState tells React to call it only once during the initial render. Subsequent renders ignore the function entirely. This avoids running expensive computations on every render.
React Server Components (RSC) run exclusively on the server. They can access databases and file systems directly, send zero JavaScript to the client, and cannot use state or effects. They are a distinct concept from SSR.
useEffect is asynchronous and runs after the browser has painted. useLayoutEffect is synchronous and fires right after DOM mutations, before the browser paints. Use useLayoutEffect only when you need to read or modify layout to avoid a visual flicker.
Without a cleanup function returning () => window.removeEventListener('resize', handleResize), the listener persists after unmount. This creates a memory leak and may call handlers that reference unmounted component state.
React favors composition over inheritance. You build flexible UIs by creating small, focused components and combining them. The children prop and render props patterns are the primary tools. React's own documentation advises against class inheritance for sharing UI logic.
React creates the ref object once on mount and returns the same object reference on every subsequent render. Because the object identity never changes, mutating .current does not trigger a re-render.
React follows a strict order: (1) the component function executes (render phase), (2) React updates the DOM (commit phase), (3) useEffect callbacks fire (after paint). This mirrors componentDidMount/componentDidUpdate in class components.
This is correct useMemo usage. expensiveFilter is only called when query changes. If allData is defined outside the component (module-level constant), it does not need to be in the dependency array because it never changes.
useCallback only prevents re-renders when the child is wrapped in React.memo. Without React.memo on Child, Parent's re-render causes Child to re-render regardless of whether onClick is the same reference. The memoization is wasted.
ref.current was set to 0 when the component first rendered and is never updated afterward. setCount schedules a re-render, but the console.log runs synchronously in the same event handler, reading the stale ref.current value of 0. The button re-renders and shows 1.
When you write <Card><p>Hello</p></Card>, React passes <p>Hello</p> as props.children to Card. The component can then render {children} wherever it wants, enabling flexible component composition patterns.
Conditional rendering means returning different JSX based on runtime conditions. Common patterns are: if/else before the return, ternary (condition ? A : B) inline, and short-circuit (condition && <Component />) for optional elements.
items.length is 0, which is falsy but React renders the number 0 as text. The && short-circuits and returns the left operand (0) when it is falsy. To fix this, use !!items.length && ... or items.length > 0 && ...
Hooks must not be called conditionally. Calling useState (or any hook) inside an if block means the hook may or may not be called depending on the condition, which violates the Rules of Hooks and breaks the hook call order React depends on.
Array.push mutates the existing array in place. React does a shallow comparison of the old and new state references. Because setItems(items) passes the same reference back, React may bail out of re-rendering. You should use setItems([...items, 'c']) instead.
React.PureComponent implements shouldComponentUpdate with a shallow props and state comparison. The equivalent for function components is React.memo, which does the same shallow props comparison and skips re-rendering when props are unchanged.
React's diffing algorithm first compares element types. If the type is the same, it updates the existing DOM node. If the type differs, it destroys the old subtree and builds a new one. The key prop helps React match elements in lists across renders.
The shorthand <> ... </> is a React.Fragment. It groups multiple children without adding any extra DOM node. The browser only sees the two <p> elements with no parent wrapper.
Every useMemo and useCallback call adds overhead: React must store the previous value, run the dependency comparison, and manage the cached closure. For cheap computations or components that always re-render anyway, this overhead outweighs the savings.
DOM layout properties like offsetWidth are only available after the DOM has been updated. useLayoutEffect runs synchronously after DOM mutations and before paint, making it the right place to read layout. Reading during render returns null because the DOM node does not yet exist.
startTransition tells React that the wrapped state update is a non-urgent transition. React can interrupt, pause, or restart the transition work if higher-priority updates (like user input) come in, keeping the UI interactive.
The render prop pattern shares code between components by passing a function prop that returns JSX. The host component calls this function and renders its result, giving the caller full control over the rendered output while the host component manages logic.
React preserves the state of a component as long as it stays mounted at the same position in the component tree with the same type and key. A parent re-rendering does not reset child state unless the child is unmounted and remounted.
Keys are only meaningful within the same parent context. React uses both type and key together when diffing. Two siblings with the same key but different types are still treated as separate elements and will each unmount and remount if they swap positions.
useMemo with [count] in the dependency array only recomputes the value when count changes between renders. If count is the same as the previous render, React returns the cached value without running the factory function.
Before React 18, only updates inside synthetic event handlers were batched. React 18 automatically batches updates from promises, setTimeout, and native events too, so multiple setState calls in any context cause a single re-render instead of one render per call.
ReactDOM.flushSync(fn) forces React to flush all state updates inside fn synchronously and immediately, bypassing automatic batching. It is useful when you need the DOM to update before reading a layout value.
The empty dependency array means the effect runs once on mount, starting the interval. The cleanup function (returning clearInterval) runs when the component unmounts, stopping the interval. This is the correct pattern for timers in useEffect.
If a lazy import rejects (e.g., network failure), React throws the error and the nearest error boundary catches it. Without an error boundary, the error surfaces as an uncaught exception. Suspense only handles the loading state, not the error state.
Array.map returns a new array of React elements, which React can render. forEach returns undefined and cannot be embedded in JSX. The for loop is not a valid JSX expression. Always include a stable key prop when mapping over lists.
Hooks can only be called inside React function components or custom hooks (functions whose name starts with 'use'). Calling useContext inside a plain utility function like fetchUser violates the Rules of Hooks and throws at runtime.
Returning null from a component renders nothing to the DOM, but the component instance (and its state) remains mounted. This is different from conditional rendering that removes the component from the tree entirely.
useReducer shines when state logic is complex: multiple related state values, transitions that depend on the current state, or when you want a Redux-like pattern for predictability. For simple independent values, useState is more concise.
React 18 batches all state updates within the same event handler into a single re-render. Both setA and setB are called in one click handler, so React processes them together and triggers only one re-render, logging 'render' once.
Data fetching belongs inside useEffect because it is a side effect. You start the fetch, then call setState when the data arrives, which triggers a re-render with the loaded data. The dependency array controls when refetching occurs.
JSX is syntactic sugar for React.createElement calls. The Babel/SWC transform converts <h1 className='title'>Hello</h1> into React.createElement('h1', { className: 'title' }, 'Hello'), which returns a plain JavaScript object describing the element.
A stale closure occurs when a function (like an effect or event handler) captures a variable's value at the time it was created, then uses that stale value on a later render where the variable has changed. The fix is either adding the value to the dependency array or using a ref.
This is the 'latest ref' pattern. Storing callback in a ref and always updating callbackRef.current means the effect runs once (empty deps) with a stable handler function, but that handler always calls the latest version of callback via the ref.
React's reconciler diffs the new virtual DOM against the previous one. Where no difference is found, it skips the corresponding DOM update. The component still re-renders (its function still runs), but React avoids unnecessary DOM mutations.
The mount phase is the initial render: the component function runs for the first time, React creates the DOM nodes, and effects with [] or no dependency run for the first time. State is initialized, and refs receive their DOM node.
When a component unmounts, React runs all cleanup functions returned from its effects. This is the right place to cancel subscriptions, clear timers, and remove event listeners. After cleanup, React removes the component's DOM nodes.
Calling useState inside an if statement is a direct violation of the Rules of Hooks. React relies on the order of hook calls being identical on every render. Conditional invocation breaks this order and causes unexpected behavior or errors.
A React element is an immutable plain object created by React.createElement (or JSX). It describes what you want on screen. A React component is a function (or class) that accepts props and returns elements. Components produce elements; elements describe the UI.
Even though both JSX branches render the same Child component type, they have different keys ('a' vs 'b'). When the key changes, React treats it as a completely different element: it unmounts the old Child and mounts a new one, resetting its state to 0.
React.memo(ChildComponent) wraps the component and performs a shallow comparison of its props between renders. If all props are the same reference, React reuses the last rendered output and skips calling the component function again.
React.memo(Component, arePropsEqual) accepts an optional second argument. If arePropsEqual(prevProps, nextProps) returns true, React skips the render. If it returns false, React re-renders. Note this is the opposite of shouldComponentUpdate's return value.
displayName is a string property on a component that React DevTools and stack traces use to identify the component. It is especially useful for higher-order components and components created with React.forwardRef or React.memo, which may otherwise show generic names.
obj === obj is trivially true because you are comparing the same variable to itself in one render. However, on each re-render, const obj = { a: 1 } creates a brand new object. memoObj, wrapped in useMemo with [], is the same object reference across all renders.
Concurrent mode makes React's rendering work interruptible. React can start rendering, pause if a higher-priority update arrives (like user input), handle that first, then return to the original work. This is the foundation for useTransition and useDeferredValue.
Hydration is the process where React takes static HTML sent from the server, builds the virtual DOM from it, and attaches event listeners without re-rendering the DOM. This makes the page interactive while keeping the fast initial load of server-rendered HTML.
useMemo uses Object.is to compare dependency values. If value is the exact same reference on the next render, useMemo returns the cached result from the first render. If value is a new object with the same contents, it is a different reference and useMemo recomputes.
When the context value changes, all components subscribed via useContext re-render, regardless of which part of the value they use. For frequently updating values, splitting context into smaller pieces or using external state managers with selector support is more efficient.
React.createElement(type, props, ...children) creates a new element. React.cloneElement(element, extraProps, ...children) takes an existing element, merges extraProps into its existing props, and returns a new element. cloneElement is often used in composition patterns.
Changing the key prop on any element (not just in lists) causes React to unmount the old instance and mount a completely new one. This is a deliberate pattern to reset component state without lifting state or using a useEffect reset.
The effect runs whenever n changes. It increments n until n reaches 3, at which point the if condition is false and setN is not called. React stops re-rendering because n stays at 3, so the effect runs once more with n=3 but does nothing.
React has no built-in usePrevious hook. The standard pattern is a custom hook that stores the value in a useRef and updates it after each render via useEffect. On the current render, the ref still holds the value from the previous render.
'use client' is a boundary directive in the React Server Components model (used with Next.js App Router). It marks a component and all its imports as client components, enabling the use of hooks, state, effects, and browser APIs.
If the component unmounts while the fetch is in flight, the .then(setData) call still fires and attempts to update state on an unmounted component. The fix is to use an AbortController or a boolean isMounted flag in the cleanup function.
props.children can be undefined (no children), a single React element (not an array), or an array. Array.prototype.map throws if children is not an array. React.Children.map handles all these cases safely, normalizing children into an iterable first.
In development mode with StrictMode, React double-invokes the lazy initializer function passed to useState to help detect side effects. You will see 'init' logged twice in the console. In production, it runs only once. The final state value is still 0.