React Error Boundary ile Hata Yönetimi

React Error Boundary ile Hata Yönetimi
React uygulamalarında render sırasında oluşan JavaScript hataları, tüm bileşen ağacını çökertebilir ve kullanıcıya boş bir ekran gösterebilir. Error Boundary bileşenleri, bu tür hataları yakalayarak uygulamanızın geri kalanının çalışmaya devam etmesini sağlar. Bu yazıda Error Boundary'leri detaylıca inceleyecek, farklı hata senaryoları için stratejiler geliştireceğiz.
Error Boundary Nedir?
Error Boundary, alt bileşen ağacında oluşan JavaScript hatalarını yakalayan, bu hataları loglayan ve hata oluştuğunda bir fallback UI gösteren React bileşenleridir. Error Boundary'ler class component olarak yazılır ve getDerivedStateFromError ile componentDidCatch lifecycle metotlarını kullanır.
Temel Error Boundary Oluşturma
import { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
// State güncelle, bir sonraki render'da fallback UI gösterilsin
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
// Hatayı bir hata raporlama servisine gönder
console.error('Error Boundary yakaladı:', error, errorInfo);
this.setState({ errorInfo });
// Hata raporlama servisi örneği
// logErrorToService(error, errorInfo.componentStack);
}
render() {
if (this.state.hasError) {
return (
this.props.fallback || (
<div className="error-fallback">
<h2>Bir şeyler ters gitti.</h2>
<p>Lütfen sayfayı yenileyin veya daha sonra tekrar deneyin.</p>
<button onClick={() => this.setState({ hasError: false })}>
Tekrar Dene
</button>
</div>
)
);
}
return this.props.children;
}
}
export default ErrorBoundary;
Error Boundary Kullanımı
Error Boundary'leri bileşen ağacınızın stratejik noktalarına yerleştirerek, hata izolasyonu sağlayabilirsiniz:
function App() {
return (
<div className="app">
{/* Üst düzey Error Boundary — tüm uygulamayı korur */}
<ErrorBoundary fallback={<AppErrorFallback />}>
<Header />
<main>
{/* Bölüm bazlı Error Boundary */}
<ErrorBoundary fallback={<SidebarError />}>
<Sidebar />
</ErrorBoundary>
{/* İçerik alanı ayrı bir boundary'de */}
<ErrorBoundary fallback={<ContentError />}>
<MainContent />
</ErrorBoundary>
</main>
<Footer />
</ErrorBoundary>
</div>
);
}
react-error-boundary Kütüphanesi
Class component yazmak istemiyorsanız, react-error-boundary kütüphanesi hook'lar ve daha modern bir API sunar:
npm install react-error-boundary
import { ErrorBoundary, useErrorBoundary } from 'react-error-boundary';
function ErrorFallback({ error, resetErrorBoundary }) {
return (
<div role="alert" className="error-fallback">
<h3>Hata Oluştu</h3>
<pre>{error.message}</pre>
<button onClick={resetErrorBoundary}>Tekrar Dene</button>
</div>
);
}
function App() {
return (
<ErrorBoundary
FallbackComponent={ErrorFallback}
onError={(error, info) => {
// Hata raporlama servisine gönder
console.error('Hata:', error);
console.error('Bileşen stack:', info.componentStack);
}}
onReset={() => {
// State'i sıfırla, cache'i temizle vb.
}}
>
<MainApp />
</ErrorBoundary>
);
}
useErrorBoundary Hook'u
Bu hook, fonksiyonel bileşenlerden programatik olarak hata fırlatmanızı sağlar. Event handler'lar ve asenkron kodlardaki hataları Error Boundary'ye yönlendirmek için kullanılır.
import { useErrorBoundary } from 'react-error-boundary';
function UserProfile({ userId }) {
const { showBoundary } = useErrorBoundary();
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId)
.then(setUser)
.catch((error) => {
// Async hatayı Error Boundary'ye yönlendir
showBoundary(error);
});
}, [userId, showBoundary]);
const handleDelete = async () => {
try {
await deleteUser(userId);
} catch (error) {
// Event handler hatasını Error Boundary'ye yönlendir
showBoundary(error);
}
};
if (!user) return <p>Yükleniyor...</p>;
return (
<div>
<h3>{user.name}</h3>
<button onClick={handleDelete}>Kullanıcıyı Sil</button>
</div>
);
}
Hata Raporlama Entegrasyonu
Production ortamında hataları takip etmek için Sentry, LogRocket veya benzeri servisleri entegre edebilirsiniz:
import * as Sentry from '@sentry/react';
// Sentry'nin kendi Error Boundary bileşeni
function App() {
return (
<Sentry.ErrorBoundary
fallback={({ error, resetError }) => (
<div>
<h2>Bir hata oluştu</h2>
<p>{error.message}</p>
<button onClick={resetError}>Tekrar Dene</button>
</div>
)}
beforeCapture={(scope) => {
scope.setTag('location', 'main-app');
}}
>
<MainApp />
</Sentry.ErrorBoundary>
);
}
// Manuel hata raporlama
function logErrorToService(error, componentStack) {
Sentry.withScope((scope) => {
scope.setExtra('componentStack', componentStack);
Sentry.captureException(error);
});
}
Gelişmiş Pattern: Reset Stratejileri
Error Boundary'yi sıfırlamak için farklı stratejiler kullanabilirsiniz:
import { ErrorBoundary } from 'react-error-boundary';
import { useQueryErrorResetBoundary } from '@tanstack/react-query';
function AppWithReactQuery() {
const { reset } = useQueryErrorResetBoundary();
return (
<ErrorBoundary
onReset={reset}
resetKeys={[/* state değişkenleri */]}
FallbackComponent={ErrorFallback}
>
<Routes />
</ErrorBoundary>
);
}
// resetKeys ile otomatik sıfırlama
function ProductPage({ productId }) {
return (
<ErrorBoundary
FallbackComponent={ErrorFallback}
resetKeys={[productId]} // productId değişince boundary sıfırlanır
>
<ProductDetails id={productId} />
</ErrorBoundary>
);
}
Suspense ile Birlikte Kullanım
Error Boundary, React Suspense ile birlikte veri yükleme hatalarını yönetmek için idealdir:
function DataSection() {
return (
<ErrorBoundary FallbackComponent={ErrorFallback}>
<Suspense fallback={<LoadingSpinner />}>
<AsyncDataComponent />
</Suspense>
</ErrorBoundary>
);
}
Error Boundary Test Etme
import { render, screen } from '@testing-library/react';
import { ErrorBoundary } from 'react-error-boundary';
function BuggyComponent() {
throw new Error('Test hatası');
}
test('Error Boundary hata durumunda fallback gösterir', () => {
// console.error'u sustur
const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
render(
<ErrorBoundary fallback={<p>Hata oluştu</p>}>
<BuggyComponent />
</ErrorBoundary>
);
expect(screen.getByText('Hata oluştu')).toBeInTheDocument();
spy.mockRestore();
});
Sonuç
Error Boundary, React uygulamalarında hata yönetiminin temel yapı taşıdır. Class component olarak yazmak yerine react-error-boundary kütüphanesini tercih ederek modern bir API'den faydalanabilirsiniz. useErrorBoundary hook'u ile asenkron ve event handler hatalarını da yakalayabilir, Sentry gibi servislerle entegre ederek production hatalarını takip edebilirsiniz. Stratejik yerleşim, reset mekanizmaları ve Suspense entegrasyonu ile kullanıcılarınıza her durumda anlamlı bir deneyim sunabilirsiniz.