memowake-front/components/common/ErrorBoundary.tsx
2025-07-29 20:38:00 +08:00

93 lines
2.3 KiB
TypeScript

import React from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
interface ErrorBoundaryProps {
children: React.ReactNode;
fallback?: React.ReactNode;
}
interface ErrorBoundaryState {
hasError: boolean;
error?: Error;
}
const translations = {
error: 'Error',
issue: 'An issue occurred',
retry: 'Retry'
};
class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('ErrorBoundary caught an error:', error, errorInfo);
}
handleRetry = () => {
this.setState({ hasError: false, error: undefined });
};
render() {
if (this.state.hasError) {
if (this.props.fallback) {
return this.props.fallback;
}
return (
<View style={styles.container}>
<Text style={styles.title}>{translations.error}</Text>
<Text style={styles.error}>
{this.state.error?.message || translations.issue}
</Text>
<TouchableOpacity style={styles.retryButton} onPress={this.handleRetry}>
<Text style={styles.retryText}>{translations.retry}</Text>
</TouchableOpacity>
</View>
);
}
return this.props.children;
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
backgroundColor: '#fff',
},
title: {
fontSize: 18,
fontWeight: '600',
marginBottom: 10,
color: '#333',
},
error: {
color: '#ff4d4f',
marginBottom: 20,
textAlign: 'center',
},
retryButton: {
backgroundColor: '#1890ff',
paddingHorizontal: 20,
paddingVertical: 10,
borderRadius: 4,
},
retryText: {
color: '#fff',
fontSize: 16,
},
});
export default ErrorBoundary;