Skip to content

Instantly share code, notes, and snippets.

@andishe-wpd
Created February 3, 2025 06:53
Show Gist options
  • Save andishe-wpd/39ddef92b3d25bf3d7d02bfabfc2f304 to your computer and use it in GitHub Desktop.
Save andishe-wpd/39ddef92b3d25bf3d7d02bfabfc2f304 to your computer and use it in GitHub Desktop.
ErrorBoundaryExample
import React from 'react';
import { DefaultErrorFallback } from './ErrorFallback/DefaultErrorFallback';
import { logError } from '@/utils/logError';
interface Props {
children: React.ReactNode;
fallback?: React.ReactNode;
onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
}
interface State {
hasError: boolean;
error: Error | null;
}
export class BaseErrorBoundary extends React.Component<Props, State> {
state = { hasError: false, error: null };
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
// Log the error
logError(error, errorInfo);
// Call the optional onError prop if provided
this.props.onError?.(error, errorInfo);
}
render() {
if (this.state.hasError) {
return this.props.fallback || <DefaultErrorFallback error={this.state.error} />;
}
return this.props.children;
}
}
import { Button } from '@headlessui/react';
import React from 'react';
interface DefaultErrorFallbackProps {
error: Error | null;
}
export const DefaultErrorFallback: React.FC<DefaultErrorFallbackProps> = ({ error }) => {
const handleRefresh = () => {
window.location.reload();
};
return (
<div className="flex flex-col items-center justify-center min-h-[400px] p-6 text-center">
<div className="mb-6">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none">
<path
d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M15 9L9 15"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M9 9L15 15"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
<h2 className="text-subtitleBase text-neutral-13 mb-2">مشکلی پیش آمده است</h2>
<p className="text-bodyBase text-neutral-9 mb-6">
{error?.message || 'خطای ناشناخته رخ داده است'}
</p>
<Button className="primaryFilled" onClick={handleRefresh}>
تلاش مجدد
</Button>
</div>
);
};
export const logError = async (error: Error, errorInfo: React.ErrorInfo) => {
try {
await fetch('http://localhost:3001/api/log-error', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: error.message,
stack: error.stack,
componentName: errorInfo.componentStack,
path: window.location.pathname,
severity: 'error',
metadata: {
timestamp: new Date(),
userAgent: navigator.userAgent
}
})
});
} catch (err) {
console.error('Failed to log error:', err);
}
};
import { BaseErrorBoundary } from './BaseErrorBoundary';
import { GlobalErrorFallback } from './ErrorFallback/GlobalErrorFallback';
export const GlobalErrorBoundary: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const handleError = (error: Error, errorInfo: React.ErrorInfo) => {
// Log to error tracking service
console.error('Global error:', error, errorInfo);
};
return (
<BaseErrorBoundary onError={handleError} fallback={<GlobalErrorFallback />}>
{children}
</BaseErrorBoundary>
);
};
import { BaseErrorBoundary } from './BaseErrorBoundary';
import { PageErrorFallback } from './ErrorFallback/PageErrorFallback';
export const PageErrorBoundary: React.FC<{ children: React.ReactNode }> = ({ children }) => {
return <BaseErrorBoundary fallback={<PageErrorFallback />}>{children}</BaseErrorBoundary>;
};
import { BaseErrorBoundary } from './BaseErrorBoundary';
import { SectionErrorFallback } from './ErrorFallback/SectionErrorFallback';
export const SectionErrorBoundary: React.FC<{ children: React.ReactNode }> = ({ children }) => {
return <BaseErrorBoundary fallback={<SectionErrorFallback />}>{children}</BaseErrorBoundary>;
};
import { useState } from 'react';
import { Button } from 'rsuite';
const TestError = () => {
const [shouldThrow, setShouldThrow] = useState(false);
if (shouldThrow) {
throw new Error('Test error thrown!');
}
return (
<div className="p-4">
<Button className="primaryFilled" onClick={() => setShouldThrow(true)}>
Throw Error
</Button>
</div>
);
};
export default TestError;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment