Basic ErrorBoundary Implementation
A foundation for catching and handling React errors:
class ErrorBoundary extends React.Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
// Log to error reporting service
console.error('ErrorBoundary caught an error:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return this.props.fallback || <DefaultErrorUI error={this.state.error} />;
}
return this.props.children;
}
}
// Usage
const App = () => {
return (
<ErrorBoundary fallback={<CustomErrorPage />}>
<MainContent />
</ErrorBoundary>
);
};
Handling Async Errors
Catch errors in async operations and propagate them to ErrorBoundary:
const useAsyncError = () => {
const [, setError] = useState();
return useCallback(
error => {
setError(() => {
throw error;
});
},
[]
);
};
const AsyncComponent = () => {
const throwError = useAsyncError();
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('/api/data');
const data = await response.json();
// Use data...
} catch (error) {
throwError(error);
}
};
fetchData();
}, []);
return <div>Loading...</div>;
};
Reusable Error Boundary Hook
Create a custom hook for error boundaries:
const useErrorBoundary = () => {
const [error, setError] = useState(null);
if (error) {
throw error;
}
return setError;
};
const ComponentWithError = () => {
const throwError = useErrorBoundary();
const handleClick = () => {
try {
riskyOperation();
} catch (error) {
throwError(error);
}
};
return <button onClick={handleClick}>Trigger Error</button>;
};
Network Error Handling
Handle API errors gracefully:
const useFetch = (url) => {
const [state, setState] = useState({
data: null,
error: null,
loading: true
});
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setState({ data, error: null, loading: false });
} catch (error) {
setState({ data: null, error, loading: false });
}
};
fetchData();
}, [url]);
return state;
};
const UserProfile = ({ userId }) => {
const { data, error, loading } = useFetch(`/api/users/${userId}`);
if (loading) return <LoadingSpinner />;
if (error) return <ErrorMessage error={error} />;
return <ProfileData user={data} />;
};
Form Error Handling
Handle form validation and submission errors:
const FormWithErrorHandling = () => {
const [errors, setErrors] = useState({});
const validate = (values) => {
const errors = {};
if (!values.email) {
errors.email = 'Required';
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) {
errors.email = 'Invalid email address';
}
return errors;
};
const handleSubmit = async (values) => {
try {
const errors = validate(values);
if (Object.keys(errors).length > 0) {
setErrors(errors);
return;
}
await submitForm(values);
} catch (error) {
setErrors({ submit: error.message });
}
};
return (
<form onSubmit={handleSubmit}>
<input type="email" />
{errors.email && <span className="error">{errors.email}</span>}
{errors.submit && (
<div className="error-banner">{errors.submit}</div>
)}
<button type="submit">Submit</button>
</form>
);
};
Global Error Handler
Catch unhandled errors application-wide:
const GlobalErrorHandler = () => {
useEffect(() => {
const handler = (event) => {
console.error(
'Unhandled error:',
event.error?.message || 'Unknown error'
);
// Prevent default browser error overlay
event.preventDefault();
// Show user-friendly error message
// You could use a global state management solution here
showErrorNotification(
'Something went wrong. Please try again later.'
);
};
window.addEventListener('error', handler);
window.addEventListener('unhandledrejection', handler);
return () => {
window.removeEventListener('error', handler);
window.removeEventListener('unhandledrejection', handler);
};
}, []);
return null;
};
// Usage in root component
const App = () => (
<>
<GlobalErrorHandler />
<RestOfApp />
</>
);
Key Error Handling Strategies
- Use ErrorBoundary for component rendering errors
- Implement async error handling with custom hooks
- Handle network errors in data fetching operations
- Validate forms and handle submission errors gracefully
- Set up global error handling for unhandled exceptions