Browse Source

fix: make ErrorBoundary reactive to network state and move OfflineBanner outside

- ErrorBoundary now tracks isOnline via state + event listeners instead
  of reading navigator.onLine once at render time, so the subtitle
  updates when the user goes back online
- OfflineBanner moved outside ErrorBoundary in rootContainer so it
  remains visible even when ErrorBoundary shows the error fallback

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
pull/11756/head
afc163 5 months ago
parent
commit
71a2b885cd
  1. 6
      src/app.tsx
  2. 24
      src/components/ErrorBoundary/index.tsx

6
src/app.tsx

@ -187,9 +187,9 @@ export const request: RequestConfig = {
export function rootContainer(container: React.ReactNode) { export function rootContainer(container: React.ReactNode) {
return ( return (
<ErrorBoundary> <>
<OfflineBanner /> <OfflineBanner />
{container} <ErrorBoundary>{container}</ErrorBoundary>
</ErrorBoundary> </>
); );
} }

24
src/components/ErrorBoundary/index.tsx

@ -20,18 +20,36 @@ function getSubTitleId(isChunkError: boolean, isOffline: boolean): string {
interface ErrorBoundaryState { interface ErrorBoundaryState {
hasError: boolean; hasError: boolean;
error: Error | null; error: Error | null;
isOnline: boolean;
} }
export default class ErrorBoundary extends React.Component< export default class ErrorBoundary extends React.Component<
{ children: React.ReactNode }, { children: React.ReactNode },
ErrorBoundaryState ErrorBoundaryState
> { > {
state: ErrorBoundaryState = { hasError: false, error: null }; state: ErrorBoundaryState = {
hasError: false,
error: null,
isOnline: typeof navigator !== 'undefined' ? navigator.onLine : true,
};
static getDerivedStateFromError(error: Error): ErrorBoundaryState { static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {
return { hasError: true, error }; 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 });
handleOffline = () => this.setState({ isOnline: false });
componentDidCatch(error: Error, info: React.ErrorInfo) { componentDidCatch(error: Error, info: React.ErrorInfo) {
console.error('[ErrorBoundary]', error, info.componentStack); console.error('[ErrorBoundary]', error, info.componentStack);
} }
@ -51,7 +69,7 @@ export default class ErrorBoundary extends React.Component<
const { error } = this.state; const { error } = this.state;
const intl = getIntl(); const intl = getIntl();
const isOffline = typeof navigator !== 'undefined' && !navigator.onLine; const isOffline = !this.state.isOnline;
const isChunkError = isChunkLoadError(error); const isChunkError = isChunkLoadError(error);
const title = intl.formatMessage({ const title = intl.formatMessage({

Loading…
Cancel
Save