Consider a client-side error boundary component in Next.js wrapping a child component that throws an error during rendering. What will the user see?
function ErrorBoundary({ children }) { const [hasError, setHasError] = React.useState(false); React.useEffect(() => { const handleError = () => setHasError(true); window.addEventListener('error', handleError); return () => window.removeEventListener('error', handleError); }, []); if (hasError) { return <div role="alert">Something went wrong.</div>; } return children; } function BuggyComponent() { throw new Error('Crash!'); } export default function Page() { return ( <ErrorBoundary> <BuggyComponent /> </ErrorBoundary> ); }
Think about what an error boundary is designed to do in React and Next.js.
An error boundary catches errors in its child components during rendering and displays a fallback UI instead of crashing the whole app. Here, the ErrorBoundary sets hasError to true and renders the fallback message.
Choose the code that correctly implements a client-side error boundary using React hooks in Next.js.
Remember that React error boundaries cannot catch errors inside event handlers or async code, so a window error listener is sometimes used.
Option A uses a window error event listener to detect errors globally on the client side and updates state to show fallback UI. This pattern works in Next.js client components. Option A is a class component which Next.js discourages for new code. Option A tries to catch errors inside useEffect which won't catch render errors. Option A does not handle errors at all.
Review the code below. Why does the error boundary not catch errors thrown inside the button's onClick handler?
function ErrorBoundary({ children }) { const [hasError, setHasError] = React.useState(false); React.useEffect(() => { const handleError = () => setHasError(true); window.addEventListener('error', handleError); return () => window.removeEventListener('error', handleError); }, []); if (hasError) { return <div>Something went wrong.</div>; } return children; } export default function Page() { return ( <ErrorBoundary> <button onClick={() => { throw new Error('Click error'); }}> Click me </button> </ErrorBoundary> ); }
Think about how React handles errors in event handlers differently from render errors.
React error boundaries catch errors during rendering, lifecycle methods, and constructors, but not inside event handlers. Also, window error events do not catch errors thrown synchronously inside React event handlers. Therefore, the error boundary does not catch the error thrown in the button's onClick.
Given the code below, what will be the value of hasError after an error event is triggered?
function ErrorBoundary({ children }) { const [hasError, setHasError] = React.useState(false); React.useEffect(() => { const handleError = () => setHasError(true); window.addEventListener('error', handleError); return () => window.removeEventListener('error', handleError); }, []); return hasError ? <div>Error occurred</div> : children; } // Somewhere else in the app, an error is thrown causing a window error event.
Consider what the event listener does when an error occurs.
The event listener calls setHasError(true) when an error event fires, so the hasError state becomes true.
Choose the best explanation for why client-side error boundaries are used in Next.js apps.
Think about what happens when a React component crashes and how error boundaries help.
Client-side error boundaries catch rendering errors in their child components and display fallback UI, preventing the whole app from crashing and improving user experience. They do not fix bugs automatically or replace try-catch in async code. Server-side rendering error handling is separate.