👨🏻‍💻👩🏻‍💻 Use Ant Design like a Pro!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

136 lines
3.7 KiB

import { getIntl } from '@umijs/max';
import { Button, Card, Result } from 'antd';
import React from 'react';
function isChunkLoadError(error: Error): boolean {
return (
error.name === 'ChunkLoadError' ||
/(?:loading|failed to load) (?:css )?chunk/i.test(error.message) ||
/Failed to fetch dynamically imported module/i.test(error.message)
);
}
function getSubTitleId(isChunkError: boolean, isOffline: boolean): string {
if (!isChunkError) return 'app.error.render.description';
return isOffline
? 'app.error.chunk.description.offline'
: 'app.error.chunk.description.online';
}
function renderErrorFallback(
error: Error,
isOnline: boolean,
onReload: () => void,
) {
const intl = getIntl();
const isOffline = !isOnline;
const isChunkError = isChunkLoadError(error);
return (
<div style={{ padding: 24 }}>
<Card variant="borderless">
<Result
status="error"
title={intl.formatMessage({
id: isChunkError
? 'app.error.chunk.title'
: 'app.error.render.title',
defaultMessage: isChunkError
? 'Failed to load page'
: 'Something went wrong',
})}
subTitle={intl.formatMessage({
id: getSubTitleId(isChunkError, isOffline),
defaultMessage:
isChunkError && isOffline
? 'Your network connection has been lost. Please check your connection and reload.'
: isChunkError
? 'Page resources failed to load. Please reload and try again.'
: 'Sorry, an error occurred on this page. Please reload or go back to the home page.',
})}
extra={[
<Button type="primary" key="reload" onClick={onReload}>
{intl.formatMessage({
id: 'app.error.reload',
defaultMessage: 'Reload Page',
})}
</Button>,
<Button href="/" key="home">
{intl.formatMessage({
id: 'app.error.home',
defaultMessage: 'Back Home',
})}
</Button>,
]}
/>
</Card>
</div>
);
}
interface ErrorBoundaryProps {
children: React.ReactNode;
}
interface ErrorBoundaryState {
hasError: boolean;
error: Error | null;
isOnline: boolean;
}
export default class ErrorBoundary extends React.Component<
ErrorBoundaryProps,
ErrorBoundaryState
> {
state: ErrorBoundaryState = {
hasError: false,
error: null,
isOnline: typeof navigator !== 'undefined' ? navigator.onLine : true,
};
static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {
return { hasError: true, error };
}
componentDidMount() {
window.addEventListener('online', this.handleOnline);
window.addEventListener('offline', this.handleOffline);
}
componentWillUnmount() {
window.removeEventListener('online', this.handleOnline);
window.removeEventListener('offline', this.handleOffline);
}
handleOnline = () => {
this.setState({ isOnline: true });
if (
this.state.hasError &&
this.state.error &&
isChunkLoadError(this.state.error)
) {
window.location.reload();
}
};
handleOffline = () => {
this.setState({ isOnline: false });
};
componentDidCatch(error: Error, info: React.ErrorInfo) {
console.error('[ErrorBoundary]', error, info.componentStack);
}
handleReload = () => {
window.location.reload();
};
render() {
if (!this.state.hasError || !this.state.error) return this.props.children;
return renderErrorFallback(
this.state.error,
this.state.isOnline,
this.handleReload,
);
}
}