Handling errors in React is crucial for creating a smooth user experience. This guide covers error boundaries, try-catch, handling async errors, logging, and more.
1. Error Boundaries (Catching UI Errors)
React does not catch errors inside components by default. Error boundaries help prevent an entire application from crashing by catching errors in a specific part of the component tree.
Example: Creating an Error Boundary
import React from "react"; class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, errorInfo) { console.error("Error caught by boundary:", error, errorInfo); } render() { if (this.state.hasError) { return <h2>Something went wrong. Please try again later.</h2>; } return this.props.children; } } export default ErrorBoundary;
Usage: Wrap Components in an Error Boundary
import ErrorBoundary from "./ErrorBoundary"; import MyComponent from "./MyComponent"; function App() { return ( <ErrorBoundary> <MyComponent /> </ErrorBoundary> ); } export default App;
This prevents the entire application from crashing when an error occurs in a specific component.
2. Handling Errors in Event Handlers
Errors inside event handlers do not crash React, but they should still be handled properly.
Example: Try-Catch in Event Handlers
function MyComponent() { const handleClick = () => { try { throw new Error("Something went wrong!"); } catch (error) { console.error("Caught error:", error); alert("An error occurred. Please try again."); } }; return <button onClick={handleClick}>Click Me</button>; }
Using try-catch prevents event-related errors from affecting the rest of the application.
3. Handling Errors in Async/Await Functions
Errors in asynchronous operations, such as API calls, need to be handled using try-catch.
Example: Try-Catch in API Calls
import { useState } from "react"; function FetchData() { const [data, setData] = useState(null); const [error, setError] = useState(null); const fetchData = async () => { try { const response = await fetch("https://api.example.com/data"); if (!response.ok) throw new Error("Failed to fetch data"); const result = await response.json(); setData(result); } catch (err) { setError(err.message); } }; return ( <div> <button onClick={fetchData}>Fetch Data</button> {error && <p style={{ color: "red" }}>Error: {error}</p>} {data && <pre>{JSON.stringify(data, null, 2)}</pre>} </div> ); }
This approach ensures that API failures do not crash the application.
4. Global Error Handling with window.onerror
For handling uncaught JavaScript errors globally, window.onerror
or window.addEventListener("error")
can be used.
Example: Global Error Logging
window.onerror = function (message, source, lineno, colno, error) { console.error("Global Error:", message, source, lineno, colno, error); };
This helps in debugging and logging uncaught errors in the application.
5. Logging and Reporting Errors
For production applications, error logging services help in tracking and diagnosing issues. Popular services include:
- Sentry – Real-time error tracking
- LogRocket – Session recording and logging
- Firebase Crashlytics – Frontend and backend error logging
Example: Logging Errors with Sentry
npm install @sentry/react
import * as Sentry from "@sentry/react"; Sentry.init({ dsn: "YOUR_SENTRY_DSN" }); function MyComponent() { const handleError = () => { try { throw new Error("Test error"); } catch (error) { Sentry.captureException(error); } }; return <button onClick={handleError}>Trigger Error</button>; }
This approach helps track errors in production applications.
6. Handling Errors in React Router (404 Pages)
If a user navigates to an invalid route, displaying a custom 404 page improves the user experience.
Example: React Router 404 Page
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; function NotFound() { return <h2>404 - Page Not Found</h2>; } function App() { return ( <Router> <Routes> <Route path="/" element={<Home />} /> <Route path="*" element={<NotFound />} /> </Routes> </Router> ); }
This ensures that users are informed when they access an invalid URL.
7. Handling Errors in Next.js
Next.js provides built-in error handling using custom error pages.
Example: Custom 500 Error Page in Next.js
- Create a
_error.js
file insidepages/
function Error({ statusCode }) { return ( <p> {statusCode ? `An error ${statusCode} occurred on the server` : "An error occurred on the client"} </p> ); } Error.getInitialProps = ({ res, err }) => { const statusCode = res ? res.statusCode : err ? err.statusCode : 404; return { statusCode }; }; export default Error;
This handles both client-side and server-side errors in Next.js applications.
Summary – React Error Handling Best Practices
- Use Error Boundaries to catch UI errors and prevent crashes
- Use try-catch in event handlers and async functions
- Implement global error logging using
window.onerror
- Use Sentry or LogRocket for logging errors in production
- Create custom 404 pages for handling invalid routes
- Handle Next.js errors using
_error.js