RSRobince Studio

React interview revision notes

UI library: components, hooks, state. Written for developers preparing for an interview who want to refresh their React fast. Free, no sign-up.

21 topics in these notes

  1. What is React?
  2. Components (functional vs class)
  3. JSX
  4. Props
  5. State (useState)
  6. Event handling
  7. Conditional rendering
  8. Lists & keys
  9. useEffect
  10. useRef
  11. useCallback & useMemo
  12. Custom hooks
  13. Context API
  14. Lifting state up
  15. Controlled vs uncontrolled
  16. Forms in React
  17. React Router (basics)
  18. Virtual DOM & reconciliation
  19. React.memo & performance
  20. Error boundaries
  21. Portals

What is React?

Simple real-life example (Understand first — very important for understanding)

  • Think of a web page as made of building blocks: a header block, a list block, a form block. Each block can show different content but works the same way.
  • React is a library that lets you build the UI from such blocks (components), keep them in sync with data, and update only what changed.
  • Real-world idea: build the screen from small, reusable pieces that react to data and user actions.

Real-world idea: UI as reusable components that update when data changes. React helps you build and maintain complex interfaces.

Technical definition

  • React is a JavaScript library for building user interfaces. Component-based: UI is built from small, reusable components.
  • Declarative: you describe what the UI should look like for a given state; React updates the DOM to match. Uses a Virtual DOM for efficient updates.
  • Developed by Meta; used with React Native for mobile. Often used with a bundler (Vite, Create React App) and state/routing libraries.

Simple practical example

Declarative: you describe what the UI should look like for a given state; React updates the DOM to match.

Code example

function App() {
  return <h1>Hello, World!</h1>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);

Why it matters

Most front-end roles expect React knowledge. "What is React?" and "Why use it?" are opening questions.

Interview tip

"React is a library for building UIs with components. Declarative; Virtual DOM for performance; unidirectional data flow."

Components (functional vs class)

Simple real-life example (Understand first — very important for understanding)

  • Like LEGO pieces: each piece (button, card, list item) is a component; you combine them to build the full page.
  • A component is a function or class that returns what to show (JSX); you can reuse it with different data (props).
  • Breaking the UI into components keeps code clear and makes it easy to change one piece without touching the rest.

Real-world idea: one piece of UI, reusable everywhere. Components are the building blocks of a React app.

Technical definition

  • Functional components: plain functions that return JSX. Preferred in modern React; use Hooks for state and effects.
  • Class components: ES6 classes extending React.Component; use this.state and lifecycle methods. Legacy; avoid for new code.
  • Components can be composed: use one component inside another. Props flow down from parent to child.

Simple practical example

Class components: ES6 classes extending React.

Code example

function Welcome({ name }) {
  return <p>Hello, {name}</p>;
}
// Usage: <Welcome name="Alice" />

Why it matters

"Functional vs class?" — always say functional + Hooks for new code. Know that class components still exist in older codebases.

Interview tip

"Prefer functional components with Hooks. Class components use this.state and lifecycle; functional use useState/useEffect."

JSX

Simple real-life example (Understand first — very important for understanding)

  • Like writing HTML inside JavaScript: you see tags (e.g. <div>, <button>) but they become function calls that create elements.
  • JSX lets you mix structure (tags), expressions in curly braces, and logic so the UI and data stay in one place.
  • It's not real HTML; it's a syntax that React turns into the actual DOM updates.

Real-world idea: describe the UI in a familiar tag-like syntax. JSX is the way you write component output in React.

Technical definition

  • JSX is syntax that looks like HTML inside JavaScript. It compiles to React.createElement() calls. One parent element per return (or use Fragment <></>).
  • Use {expression} for dynamic values. className instead of class; htmlFor instead of for. camelCase for event handlers: onClick, onChange.
  • JSX prevents injection by default: values are escaped. Dangerously setting HTML: dangerouslySetInnerHTML (avoid unless necessary).

Simple practical example

Use {expression} for dynamic values.

Code example

const name = "Alice";
return (
  <div className="card">
    <h1>{name}</h1>
    <button onClick={() => alert('hi')}>Click</button>
  </div>
);

Why it matters

Every React component uses JSX (or equivalent). Knowing className vs class and expression syntax is basic.

Interview tip

"JSX compiles to createElement. Use className, camelCase events; expressions in curly braces. One root or Fragment."

Props

Simple real-life example (Understand first — very important for understanding)

  • Like passing instructions to a component: "Here is the title," "Here is the list of items." The parent gives, the child receives.
  • Props are read-only; the child cannot change them. They flow down from parent to child.
  • Use props to customize how a component looks or what data it shows so the same component can be reused with different content.

Real-world idea: pass data and settings into a component. Props are how parents configure and feed data to children.

Technical definition

  • Props are read-only inputs passed from parent to child. Like function arguments. Access as props.name or destructure: function Child({ name }).
  • Props are immutable in the child — do not modify them. Parent owns the data; child displays or notifies via callbacks passed as props.
  • children is a special prop: content between opening and closing tags. props.children can be a single element, array, or nothing.

Simple practical example

Props are immutable in the child — do not modify them.

Code example

function Card({ title, children }) {
  return (
    <div>
      <h2>{title}</h2>
      {children}
    </div>
  );
}

Why it matters

Data flow in React is unidirectional: parent → child via props. "How do you pass data?" — props. "Can child change props?" — no.

Interview tip

"Props are read-only, passed parent to child. Use destructuring. children for content between tags."

State (useState)

Simple real-life example (Understand first — very important for understanding)

  • Like a component's memory: "Is the modal open?" "What did the user type?" State holds values that can change and that the component cares about.
  • When state changes, React re-renders that part of the UI so the screen stays in sync with the data.
  • State is private to the component; only that component can update it (unless you lift it up or use context).

Real-world idea: data that can change and that drives what the component shows. State is the component's own memory.

Technical definition

  • State is data that can change over time and triggers re-renders when updated. In functional components: const [value, setValue] = useState(initial).
  • setValue(newValue) or setValue(prev => prev + 1) for updates. State updates are asynchronous and batched; use functional updates when new state depends on previous.
  • Each component instance has its own state. Lifting state up = move state to a common parent when siblings need to share it.

Simple practical example

setValue(newValue) or setValue(prev => prev + 1) for updates.

Code example

const [count, setCount] = useState(0);
return (
  <button onClick={() => setCount(c => c + 1)}>
    Count: {count}
  </button>
);

Why it matters

useState is the first Hook you use. "How do you add state?" — useState. Know when to use functional updates (e.g. increment).

Interview tip

"useState(initial) returns [value, setter]. Use setter with function when new state depends on previous. Updates are batched."

Event handling

Simple real-life example (Understand first — very important for understanding)

  • Like a button that says "when I'm clicked, do this": the user does something (click, type, submit), and you run a function in response.
  • You pass a function (e.g. onClick, onChange) to the element; React calls it when the event happens, often to update state or call an API.
  • Handlers are where you connect user actions to your app's behavior.

Real-world idea: respond to user actions. Event handlers connect clicks, input, and form submits to your logic and state.

Technical definition

  • React uses synthetic events: same interface as DOM events but cross-browser. Pass a function as onClick, onChange, etc., not a string.
  • Handler receives the event object. Call e.preventDefault() to prevent default (e.g. form submit). Don't need addEventListener — declare in JSX.
  • To pass extra arguments: onClick={() => handleClick(id)} or onClick={handleClick.bind(null, id)}. Arrow avoids binding in constructor (class) or re-binding.

Simple practical example

Handler receives the event object.

Code example

<input onChange={(e) => setName(e.target.value)} />
<button onClick={() => submit(id)}>Submit</button>

Why it matters

Event handlers are in every interactive component. Know camelCase, passing args, and that React pools events (don't use e async).

Interview tip

"Use camelCase (onClick). Pass function, not call. Synthetic events; e.persist() if you need e in async (rare)."

Conditional rendering

Simple real-life example (Understand first — very important for understanding)

  • Like showing different things depending on the situation: "If logged in, show the dashboard; otherwise show the login form."
  • You use conditions (if/else, ternary, &&) in your JSX or before return to decide what to render.
  • Conditional rendering keeps the UI in sync with state and permissions.

Real-world idea: show one thing or another based on data or state. Conditional rendering is how you switch between views or messages.

Technical definition

  • Use JavaScript: {condition && <Component />} or {condition ? <A /> : <B />}. Early return in component: if (!user) return null;.
  • Falsy gotcha: count && <span>...</span> renders 0 when count is 0. Prefer count > 0 && ... or ternary.
  • Can assign JSX to a variable and return it, or use IIFE for complex logic (usually better to split into subcomponents).

Simple practical example

Falsy gotcha: count && <span>.

Code example

{isLoading ? <Spinner /> : <List items={items} />}
{error && <p className="error">{error}</p>}

Why it matters

Conditional UI is everywhere (loading, error, empty state). Know && and ternary; avoid rendering 0 by mistake.

Interview tip

"Use condition && JSX or ternary. Watch out: 0 is falsy so count && ... can show 0."

Lists & keys

Simple real-life example (Understand first — very important for understanding)

  • Like a roster: you have an array of items and you want to show one block per item (e.g. one row per user).
  • You map over the array and return a component for each item; React needs a stable key on each item so it can track which row is which when the list changes.
  • Keys should be unique among siblings and stable (e.g. id), not the array index, when the list can be reordered or filtered.

Real-world idea: render one component per item in a list. Keys help React update the list efficiently when items change.

Technical definition

  • Render lists with array.map() returning JSX. Each top-level element in the list should have a unique key prop (e.g. key={item.id}).
  • Keys help React identify which items changed/added/removed for efficient reconciliation. Use stable, unique IDs — avoid array index as key when list can reorder or change.
  • Keys must be on the element you return from map, not necessarily on a child. Keys are not passed as props to the component.

Simple practical example

Keys help React identify which items changed/added/removed for efficient reconciliation.

Code example

{items.map(item => (
  <li key={item.id}>{item.name}</li>
))}

Why it matters

"Why keys?" and "Can we use index as key?" — common. Use id when possible; index only for static lists that don't reorder.

Interview tip

"Keys must be unique among siblings; stable identity. Prefer id over index to avoid bugs when list order changes."

useEffect

Simple real-life example (Understand first — very important for understanding)

  • Like a side effect that runs after the component is on screen: "When this component mounts, fetch data" or "When this value changes, sync with the server."
  • useEffect runs after render; you list which values it depends on so it runs again when those change (or once on mount if the list is empty).
  • Use it for fetching, subscriptions, or any action that should happen in response to being on screen or to a change in props/state.

Real-world idea: do something after render or when something changes. useEffect is for side effects like fetching or subscribing.

Technical definition

  • useEffect(() => { ... }, [deps]) runs after render. No deps array = run after every render. Empty array [] = run once (mount). Array with values = run when those values change.
  • Return a cleanup function to run on unmount or before re-running effect: return () => clearInterval(id);. Use for subscriptions, timers, listeners.
  • Common mistakes: missing deps (stale closure), deps that change every render (infinite loop), forgetting cleanup (memory leaks).

Simple practical example

Return a cleanup function to run on unmount or before re-running effect: return () => clearInterval(id);.

Code example

useEffect(() => {
  const sub = api.subscribe(id, setData);
  return () => sub.unsubscribe();
}, [id]);

Why it matters

useEffect is for side effects (fetch, subscribe, DOM). "When does useEffect run?" and dependency array are standard questions.

Interview tip

"useEffect runs after paint. Deps: none = every render, [] = mount only, [a,b] = when a or b change. Return cleanup for subscriptions."

useRef

Simple real-life example (Understand first — very important for understanding)

  • Like a sticky note that doesn't trigger a re-render: you want to keep a value (e.g. a DOM node, a timer ID) across renders without the component re-rendering when it changes.
  • useRef gives you a box that persists; changing .current does not cause a re-render. Use for DOM refs, timers, or keeping a previous value.
  • Refs are for "remember this" without making the UI depend on it.

Real-world idea: hold a value that doesn't drive the UI. useRef is for DOM refs, timers, and similar storage.

Technical definition

  • useRef(initialValue) returns a mutable object { current: value } that persists across re-renders and does not trigger re-render when updated.
  • Use for: DOM reference (ref={inputRef}, then inputRef.current.focus()), storing previous value, or any mutable value that shouldn't cause re-render.
  • Refs are for "escape hatch" — don't overuse for state that should drive UI; use useState instead.

Simple practical example

Use for: DOM reference (ref={inputRef}, then inputRef.

Code example

const inputRef = useRef(null);
useEffect(() => inputRef.current?.focus(), []);
return <input ref={inputRef} />;

Why it matters

"When do you use useRef vs useState?" — ref when you need to hold something without re-render (DOM node, interval ID, prev value).

Interview tip

"useRef: mutable .current, no re-render. Use for DOM refs, timers, or keeping previous value. useState when UI must update."

useCallback & useMemo

Simple real-life example (Understand first — very important for understanding)

  • Like avoiding unnecessary work: if a heavy computation or a callback only depends on certain inputs, you can memoize so it's only redone when those inputs change.
  • useCallback memoizes a function; useMemo memoizes a value. Both take a dependency array so React knows when to recompute.
  • Use them when you've measured and found unnecessary re-renders or repeated work; don't overuse.

Real-world idea: skip recomputing when inputs haven't changed. useCallback and useMemo optimize when needed.

Technical definition

  • useCallback(fn, deps) returns a memoized function — same reference until deps change. Use when passing callbacks to optimized children (React.memo) to avoid unnecessary re-renders.
  • useMemo(() => compute(a, b), [a, b]) returns a memoized value. Use for expensive computations that depend on props/state. Don't use for every small calc — only when it helps.
  • Both depend on dependency array. Wrong deps = stale closures or unnecessary recalc. Don't over-optimize; measure first.

Simple practical example

useMemo(() => compute(a, b), [a, b]) returns a memoized value.

Code example

const handleClick = useCallback(() => doSomething(id), [id]);
const sorted = useMemo(() => items.slice().sort(...), [items]);

Why it matters

"What's the difference between useCallback and useMemo?" — callback memoizes function, memo memoizes value. Used with React.memo for performance.

Interview tip

"useCallback = memoized function; useMemo = memoized value. Use when passing to memo'd children or expensive computation."

Custom hooks

Simple real-life example (Understand first — very important for understanding)

  • Like extracting a repeated pattern: if several components do the same thing (e.g. fetch data, track window size), put that logic in a function that uses hooks.
  • A custom hook is a function whose name starts with use and that can call other hooks; it lets you reuse stateful logic without duplicating code.
  • Same rules as hooks: call at the top level, only from React code (components or other hooks).

Real-world idea: reuse state and effects in a function. Custom hooks keep components simple and logic reusable.

Technical definition

  • Custom hook = function whose name starts with use and that can call other Hooks. Encapsulates reusable stateful logic (e.g. form field, fetch, subscription).
  • Each call to the hook gets its own state (Hooks are per-component instance). Share logic without sharing state unless you lift it or use context.
  • Examples: useLocalStorage, useDebounce, useFetch. Keep them focused and testable.

Simple practical example

Each call to the hook gets its own state (Hooks are per-component instance).

Code example

function useCounter(initial = 0) {
  const [count, setCount] = useState(initial);
  const inc = () => setCount(c => c + 1);
  return [count, inc];
}

Why it matters

"What is a custom hook?" — reuse logic that uses Hooks. Demonstrates understanding of rules of Hooks (only call at top level, from React functions).

Interview tip

"Custom hook: function starting with 'use' that uses other Hooks. Reuse stateful logic; each component gets its own state."

Context API

Simple real-life example (Understand first — very important for understanding)

  • Like a notice board that many components can read without passing props through every level: theme, current user, language.
  • You create a context, provide a value at the top, and any component in the tree can consume it without prop drilling.
  • Use for data that is "global" to a part of the tree; for frequently changing data, consider state management or composition.

Real-world idea: share data through the tree without passing props. Context is for theme, user, or other widely needed data.

Technical definition

  • Context provides a way to pass data through the tree without prop drilling. createContext(default), Provider wraps tree, consumers use useContext(MyContext) or Consumer.
  • Use for theme, locale, auth user — data that many components need. Avoid putting frequently changing data in one big context (causes wide re-renders); split contexts or use state library.
  • Context does not replace Redux for complex global state; it's for "read-heavy" shared data. Value change re-renders all consumers.

Simple practical example

Use for theme, locale, auth user — data that many components need.

Code example

const ThemeContext = createContext('light');
// Provider: <ThemeContext.Provider value="dark">...</ThemeContext.Provider>
// Consumer: const theme = useContext(ThemeContext);

Why it matters

"How do you avoid prop drilling?" — Context. "When not to use Context?" — when value changes often and tree is deep (consider state library or composition).

Interview tip

"Context: createContext, Provider, useContext. Good for theme/auth/locale. Splitting context or memoizing value reduces re-renders."

Lifting state up

Simple real-life example (Understand first — very important for understanding)

  • When two components need the same data (e.g. two siblings both need the selected item), that data can't live in just one of them.
  • You "lift" the state up to the nearest common parent; the parent holds the state and passes it down (and a setter) so both children stay in sync.
  • Lifting state keeps a single source of truth when multiple components depend on the same value.

Real-world idea: put shared state in the common parent. Lifting state keeps siblings in sync with one source of truth.

Technical definition

  • When two or more components need to share state, move that state to their common ancestor. Pass state down as props and pass updater (setState or callback) so children can notify changes.
  • Single source of truth: one place owns the state; others receive and optionally request updates. Keeps data flow predictable.
  • If lifting makes the tree heavy (too many props through middle components), consider Context or a state library.

Simple practical example

Single source of truth: one place owns the state; others receive and optionally request updates.

Code example

function Parent() {
  const [value, setValue] = useState('');
  return (
    <>
      <ChildA value={value} />
      <ChildB onChange={setValue} />
    </>
  );
}

Why it matters

"How do siblings share state?" — lift state to parent. Very common pattern in forms and filters.

Interview tip

"Lift state to the closest common parent. Pass state down, pass setter or callback so children can update."

Controlled vs uncontrolled

Simple real-life example (Understand first — very important for understanding)

  • Controlled: the input's value comes from state; you update state on change, so React fully controls what is shown and what happens.
  • Uncontrolled: the input keeps its own value in the DOM; you read it when you need it (e.g. on submit) via a ref.
  • Controlled is the usual React way (single source of truth); uncontrolled is simpler when you only need the value at one moment.

Real-world idea: who owns the input value. Controlled = React state; uncontrolled = DOM, read when needed.

Technical definition

  • Controlled: input value is driven by React state (value={name} + onChange). Single source of truth; easy to validate and transform.
  • Uncontrolled: input keeps its own state in the DOM; you read it via ref when needed (e.g. ref.current.value on submit). Simpler for one-off forms or file input.
  • React recommends controlled for most form inputs. Uncontrolled is fine for file inputs or when integrating with non-React code.

Simple practical example

Uncontrolled: input keeps its own state in the DOM; you read it via ref when needed (e.

Code example

// Controlled
const [name, setName] = useState('');
<input value={name} onChange={e => setName(e.target.value)} />

// Uncontrolled
const ref = useRef();
<input ref={ref} />  // ref.current.value when needed

Why it matters

"Controlled vs uncontrolled component?" — controlled = value from state; uncontrolled = DOM holds value, read via ref.

Interview tip

"Controlled: value + onChange from state. Uncontrolled: ref to read DOM value. Prefer controlled for validation and consistency."

Forms in React

Simple real-life example (Understand first — very important for understanding)

  • Like a paper form: user fills fields, you validate (required, format), and on submit you collect all values and send them (e.g. to an API).
  • In React you often keep form fields in state (controlled), validate on change or submit, and show errors next to fields or at the top.
  • Handling submit (preventDefault), validation, and error state keeps forms predictable and user-friendly.

Real-world idea: collect and validate user input, then submit. Forms in React use state, handlers, and validation.

Technical definition

  • Controlled approach: one state per field (or one object). onChange updates state; onSubmit on form prevents default and handles submit. Validate on submit or on blur.
  • For many fields: useState({ name: '', email: '' }) and setForm(f => ({ ...f, [e.target.name]: e.target.value })). Or use a form library (React Hook Form, Formik).
  • Checkboxes/radios: value and checked; select: value on <select> and option values. Handle multi-select with array in state.

Simple practical example

For many fields: useState({ name: '', email: '' }) and setForm(f => ({ .

Code example

<form onSubmit={e => { e.preventDefault(); submit(form); }}>
  <input name="email" value={form.email} onChange={handleChange} />
  <button type="submit">Submit</button>
</form>

Why it matters

Forms are common. Know controlled pattern, preventDefault on submit, and when to use a form library for complex forms.

Interview tip

"Controlled inputs, one state object for form, preventDefault in onSubmit. For complex forms consider React Hook Form."

React Router (basics)

Simple real-life example (Understand first — very important for understanding)

  • Like different pages in an app: URL changes (e.g. /about, /users/5), and the app shows the right component for that URL.
  • A router library (e.g. React Router) maps URLs to components and keeps the browser URL in sync with what's on screen.
  • So you get bookmarkable, shareable links and back/forward navigation without full page reloads.

Real-world idea: one app, many URLs. A router maps the URL to the right component and keeps navigation in sync.

Technical definition

  • React Router provides declarative routing: BrowserRouter, Routes, Route path="..." element={<Page />}". Link to="..." for navigation without full reload.
  • useParams() for route params (e.g. /user/:id). useNavigate() for programmatic navigation. useLocation() for current path/search.
  • Nested routes: Route with path and child Routes; use Outlet to render child route component.

Simple practical example

useParams() for route params (e.

Code example

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/user/:id" element={<User />} />
</Routes>
// In User: const { id } = useParams();

Why it matters

SPAs need routing. "How do you do routing in React?" — React Router; know Link, Route, useParams, useNavigate.

Interview tip

"React Router: BrowserRouter, Routes, Route, Link. useParams for :id, useNavigate for programmatic nav, Outlet for nested routes."

Virtual DOM & reconciliation

Simple real-life example (Understand first — very important for understanding)

  • Like making a quick sketch of what the page should look like, then comparing it to the last sketch and only changing what's different.
  • React keeps a lightweight copy of the DOM (virtual DOM), computes the new version when state changes, and updates the real DOM only where needed.
  • That way you describe the full UI declaratively, and React figures out the minimal updates for performance.

Real-world idea: describe the UI; React updates only what changed. The virtual DOM enables efficient updates.

Technical definition

  • Virtual DOM: lightweight representation of the real DOM in memory. On state change, React builds a new virtual tree and diffs it with the previous one.
  • Reconciliation: process of comparing two virtual trees and computing minimal updates to the real DOM. Batch updates for efficiency. Keys help identify list items.
  • React does not necessarily update the whole tree — only what changed. Still, avoid unnecessary re-renders (React.memo, useMemo, splitting context).

Simple practical example

Reconciliation: process of comparing two virtual trees and computing minimal updates to the real DOM.

Code example

// Concept: state change → new VDOM tree → diff with previous → patch real DOM (batched)

Why it matters

"What is Virtual DOM?" and "How does React update the DOM?" are classic questions. Know diffing and batching.

Interview tip

"Virtual DOM is a lightweight copy of the DOM; React diffs it and patches only changed parts. Keys help list reconciliation. Updates are batched."

React.memo & performance

Simple real-life example (Understand first — very important for understanding)

  • Like avoiding unnecessary work: don't re-render the whole tree if only one part changed; don't recompute heavy results if inputs are the same.
  • Techniques: memo, useMemo, useCallback, splitting components so only the part that needs new data re-renders, and listing dependencies correctly.
  • Measure first (e.g. React DevTools); then optimize where it matters.

Real-world idea: re-render only what needs to. Performance in React is about minimizing work and targeting updates.

Technical definition

  • React.memo(Component) memoizes the component: re-renders only when props change (shallow compare). Use when parent re-renders often but props are stable.
  • If you pass inline objects/functions as props, they are new every render so memo has no effect. Pair with useCallback/useMemo for stable references.
  • Other tips: lazy load routes (React.lazy + Suspense), virtualize long lists, avoid inline object/function props in hot paths.

Simple practical example

If you pass inline objects/functions as props, they are new every render so memo has no effect.

Code example

const ExpensiveChild = React.memo(function ExpensiveChild({ data }) {
  return <div>{/* heavy render */}</div>;
});

Why it matters

"How do you optimize re-renders?" — React.memo for pure components; useCallback/useMemo for stable props. Don't memo everything — measure.

Interview tip

"React.memo avoids re-render when props are same (shallow). Use with useCallback/useMemo so props are stable. Profile before over-optimizing."

Error boundaries

Simple real-life example (Understand first — very important for understanding)

  • When a component throws, the whole app doesn't have to crash; an error boundary catches the error in its child tree and can show a fallback UI.
  • You define a component that implements getDerivedStateFromError (or use a library) and wrap the part of the tree you want to protect.
  • So one broken component shows a message or retry instead of a white screen.

Real-world idea: catch errors in a part of the tree and show a fallback. Error boundaries keep the rest of the app running.

Technical definition

  • Error boundaries catch JavaScript errors in child tree and show fallback UI instead of crashing. Implement as class component with static getDerivedStateFromError and/or componentDidCatch.
  • They do not catch errors in event handlers, async code, or SSR. Only in rendering, lifecycle, and constructors of children.
  • Wrap critical sections (e.g. a feature route) in an error boundary so one broken component doesn't take down the whole app.

Simple practical example

They do not catch errors in event handlers, async code, or SSR.

Code example

class ErrorBoundary extends React.Component {
  state = { hasError: false };
  static getDerivedStateFromError() { return { hasError: true }; }
  render() {
    if (this.state.hasError) return <h1>Something went wrong.</h1>;
    return this.props.children;
  }
}

Why it matters

"How do you handle errors in React?" — error boundary for render errors; try/catch for event handlers and async.

Interview tip

"Error boundary: class component with getDerivedStateFromError/componentDidCatch. Catches render/lifecycle errors; not events or async."

Portals

Simple real-life example (Understand first — very important for understanding)

  • Like rendering a component in a different place in the DOM: e.g. a modal that should appear at the top level of the page, not deep inside a sidebar.
  • Portals let you keep the component in the React tree (so it can use context and state) but render its output somewhere else in the DOM.
  • Use for modals, tooltips, or any UI that should break out of its parent's overflow or z-index.

Real-world idea: render a component's output somewhere else in the page. Portals are for modals and overlays.

Technical definition

  • ReactDOM.createPortal(child, container) renders child into a different DOM container (e.g. a div outside root). Useful for modals, tooltips, dropdowns (escape overflow/z-index).
  • Event bubbling still works from portal to React tree parent — so click inside modal (in portal) bubbles to the React component that rendered the portal.
  • Portal doesn't change the React tree; only the DOM mount point. Useful for accessibility (e.g. render modal into document.body).

Simple practical example

Event bubbling still works from portal to React tree parent — so click inside modal (in portal) bubbles to the React component that rendered the portal.

Code example

return createPortal(
  <div className="modal">{content}</div>,
  document.body
);

Why it matters

"How do you render a modal outside the root div?" — createPortal. Often asked for modals and overlays.

Interview tip

"createPortal(child, domNode) renders into another DOM node. Use for modals so they're not clipped by overflow. Events still bubble to React parent."

More Frontend notes

HTML · CSS · JavaScript · JavaScript in the Browser · TypeScript · Angular · All developer notes