We use cookies to enhance your experience on the site
CodeWorlds

Advanced Error Handling Patterns

In this lesson, we'll explore advanced error handling techniques that you can apply in complex React applications. These patterns are like advanced safety systems on a space station - multi-layered, intelligent, and flexible.

Error Monitoring and Logging

In production, you need to know about errors immediately. Integrate Error Boundary with a monitoring system:

1class MonitoredErrorBoundary extends React.Component {
2  constructor(props) {
3    super(props);
4    this.state = { hasError: false, error: null, errorId: null };
5  }
6
7  static getDerivedStateFromError(error) {
8    return { hasError: true, error };
9  }
10
11  componentDidCatch(error, errorInfo) {
12    // Generate a unique error ID
13    const errorId = Date.now().toString(36);
14    this.setState({ errorId });
15
16    // Send to monitoring service
17    logErrorToService({
18      errorId,
19      message: error.message,
20      stack: error.stack,
21      componentStack: errorInfo.componentStack,
22      timestamp: new Date().toISOString(),
23      url: window.location.href,
24      userAgent: navigator.userAgent
25    });
26  }
27
28  render() {
29    if (this.state.hasError) {
30      return (
31        <div className="error-report">
32          <h3>An error occurred</h3>
33          <p>Error code: {this.state.errorId}</p>
34          <p>Our team has been notified.</p>
35          <button onClick={() => this.setState({ hasError: false })}>
36            Try again
37          </button>
38        </div>
39      );
40    }
41    return this.props.children;
42  }
43}

Context-aware Error Handling

Different parts of the application may require different error handling:

1import { createContext, useContext } from 'react';
2
3const ErrorContext = createContext({
4  onError: (error) => console.error(error),
5  severity: 'normal'
6});
7
8function useErrorHandler() {
9  const { onError, severity } = useContext(ErrorContext);
10
11  return (error) => {
12    if (severity === 'critical') {
13      // For critical sections - send an alert
14      sendAlert(error);
15    }
16    onError(error);
17  };
18}
19
20// Usage
21function CriticalSection({ children }) {
22  return (
23    <ErrorContext.Provider value={{
24      onError: (err) => sendToMonitoring(err),
25      severity: 'critical'
26    }}>
27      <ErrorBoundary>
28        {children}
29      </ErrorBoundary>
30    </ErrorContext.Provider>
31  );
32}

Error Recovery Strategies

Strategy 1: Automatic Component Refresh

1function AutoRecoveryBoundary({ children, maxRetries = 3 }) {
2  const [retryCount, setRetryCount] = useState(0);
3  const [key, setKey] = useState(0);
4
5  const handleReset = () => {
6    if (retryCount < maxRetries) {
7      setRetryCount(prev => prev + 1);
8      setKey(prev => prev + 1); // Forces remount
9    }
10  };
11
12  return (
13    <ErrorBoundary
14      key={key}
15      FallbackComponent={({ error }) => (
16        <div>
17          <p>Error: {error.message}</p>
18          {retryCount < maxRetries ? (
19            <button onClick={handleReset}>
20              Try again ({maxRetries - retryCount} attempts remaining)
21            </button>
22          ) : (
23            <p>Failed to fix the error. Contact support.</p>
24          )}
25        </div>
26      )}
27    >
28      {children}
29    </ErrorBoundary>
30  );
31}

Strategy 2: Fallback to Simpler Version

1function ChartWithFallback({ data }) {
2  return (
3    <ErrorBoundary
4      FallbackComponent={() => (
5        // Instead of an interactive chart, show a simple table
6        <table>
7          <thead><tr><th>Name</th><th>Value</th></tr></thead>
8          <tbody>
9            {data.map(item => (
10              <tr key={item.id}>
11                <td>{item.name}</td>
12                <td>{item.value}</td>
13              </tr>
14            ))}
15          </tbody>
16        </table>
17      )}
18    >
19      <InteractiveChart data={data} />
20    </ErrorBoundary>
21  );
22}

Global Error Handling

Catch unhandled errors at the global level:

1// In the main application file
2useEffect(() => {
3  const handleUnhandledError = (event) => {
4    console.error('Unhandled error:', event.error);
5    // Send to monitoring
6  };
7
8  const handleUnhandledRejection = (event) => {
9    console.error('Unhandled promise rejection:', event.reason);
10    // Send to monitoring
11  };
12
13  window.addEventListener('error', handleUnhandledError);
14  window.addEventListener('unhandledrejection', handleUnhandledRejection);
15
16  return () => {
17    window.removeEventListener('error', handleUnhandledError);
18    window.removeEventListener('unhandledrejection', handleUnhandledRejection);
19  };
20}, []);

Pattern Summary

| Pattern | When to Use | |---------|-------------| | Error Boundary | Component rendering errors | | try/catch | Event handlers and synchronous code | | useErrorBoundary | Asynchronous errors in Error Boundary | | Retry | Unstable network connections | | Fallback content | Optional data | | Global handler | Unexpected errors |

Go to CodeWorlds