Profiling & Optimization — Series 3

Preview — 3 of 10 questions

What is an Error Boundary, and what does it actually catch?

javascript
class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) return <h2>Something went wrong.</h2>;
    return this.props.children;
  }
}
AIt catches every JavaScript error anywhere in the app, including errors thrown inside setTimeout callbacks or rejected Promises
BIt is a React hook that replaces try/catch for asynchronous code
CIt prevents errors from occurring in the first place by validating props before rendering
DIt catches rendering errors thrown by any component in its subtree — during render, in lifecycle methods, or in constructors — and shows a fallback UI instead of letting the crash propagate and unmount the whole tree

Why is incrementing renderCount directly in the component body considered unsafe in React 18+, even though it seems to work in a quick manual test?

javascript
let renderCount = 0;

function Counter() {
  renderCount++; // ← side effect during render
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(c => c + 1)}>{renderCount}</button>;
}
AThis crashes immediately — React explicitly disallows any variable mutation during render
BReact's concurrent features mean a component's function body can be invoked more than once for what's conceptually a single commit (development-only Strict Mode double-invoking, or a render being interrupted and retried for a transition or a Suspense boundary) — a render function is expected to be a pure function of props and state, and a side effect that mutates external state, like renderCount here, fires an extra, uncontrolled number of times, producing a count that no longer corresponds 1:1 with actual commits to the screen
CThis is completely safe forever — JavaScript allows mutating any variable from anywhere, and React places no additional constraints on that
DThis only matters for class components reading this.state directly — function components using hooks are exempt from this concern

Does wrapping Panel in React.memo prevent it from re-rendering every time Parent's count changes, given that <p>Static content</p> never visually changes?

javascript
const Panel = React.memo(function Panel({ children }) {
  return <div className="panel">{children}</div>;
});

function Parent() {
  const [count, setCount] = useState(0);
  return (
    <>
      <button onClick={() => setCount(c => c + 1)}>{count}</button>
      <Panel><p>Static content</p></Panel>
    </>
  );
}
ANo — children is itself a prop, and <p>Static content</p> written inline between <Panel> and </Panel> is a fresh JSX element created on every render of Parent; React.memo's default shallow comparison sees a new children reference each time and re-renders Panel regardless of how visually static that content looks
BYes — React.memo recognizes that <p>Static content</p> never changes textually and skips re-rendering
CYes, but only because children is a special prop that React.memo always excludes from its comparison
DNo, but only because Panel destructures { children } instead of reading props.children directly — reading props.children would fix it

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.