Skip to content

Commit

Permalink
feat: better route error boundary
Browse files Browse the repository at this point in the history
  • Loading branch information
zetavg committed Feb 26, 2025
1 parent f234464 commit f02f686
Showing 1 changed file with 69 additions and 10 deletions.
79 changes: 69 additions & 10 deletions packages/one/src/router/useScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
ScreenListeners,
} from '@react-navigation/native'
import React, { memo, Suspense, useId } from 'react'
import { Text } from 'react-native'
import { SafeAreaView, ScrollView, View, TouchableOpacity, Text } from 'react-native'
import { ServerContextScript } from '../server/ServerContextScript'
import { getPageExport } from '../utils/getPageExport'
import { EmptyRoute } from '../views/EmptyRoute'
Expand Down Expand Up @@ -374,33 +374,92 @@ function routeToScreen(
)
}

type RouteErrorBoundaryState = { hasError: boolean; error: any; errorInfo: any }

const ROUTE_ERROR_BOUNDARY_INITIAL_STATE = {
hasError: false,
error: null,
errorInfo: null,
}

class RouteErrorBoundary extends React.Component<
{ children: React.ReactNode; routeName: string },
{ hasError: boolean; error: any }
RouteErrorBoundaryState
> {
constructor(props) {
super(props)
this.state = { hasError: false, error: null }
this.state = ROUTE_ERROR_BOUNDARY_INITIAL_STATE
}

static getDerivedStateFromError(error) {
return { hasError: true, error }
}

componentDidCatch(error, info) {
componentDidCatch(error, errorInfo) {
console.error(
`Error occurred while running route ${this.props.routeName}: ${
`Error occurred while running route "${this.props.routeName}": ${
error instanceof Error ? error.message : error
}`,
error,
info.componentStack
}\n\n${error.stack}\n\nComponent Stack:\n${errorInfo.componentStack}`
)
this.setState({ errorInfo })
}

clearError() {
this.setState(ROUTE_ERROR_BOUNDARY_INITIAL_STATE)
}

render() {
if (this.state.hasError) {
const error = this.state.error
return <Text>Error: {error instanceof Error ? error.message : error}</Text>
const { error, errorInfo } = this.state
return (
<SafeAreaView style={{ backgroundColor: '#000' }}>
<View style={{ margin: 16, gap: 16 }}>
<Text
style={{
alignSelf: 'flex-start',
padding: 5,
margin: -5,
backgroundColor: 'red',
color: 'white',
fontSize: 20,
fontFamily: 'monospace',
}}
>
Error on route "{this.props.routeName}"
</Text>
<Text style={{ color: 'white', fontSize: 16, fontFamily: 'monospace' }}>
{error instanceof Error ? error.message : error}
</Text>
<TouchableOpacity onPress={this.clearError.bind(this)}>
<Text
style={{
alignSelf: 'flex-start',
margin: -6,
padding: 6,
backgroundColor: 'white',
color: 'black',
fontSize: 14,
fontFamily: 'monospace',
}}
>
Retry
</Text>
</TouchableOpacity>
<ScrollView contentContainerStyle={{ gap: 12 }}>
{error instanceof Error ? (
<Text style={{ color: 'white', fontSize: 12, fontFamily: 'monospace' }}>
{error.stack}
</Text>
) : null}
{errorInfo?.componentStack ? (
<Text style={{ color: 'white', fontSize: 12, fontFamily: 'monospace' }}>
Component Stack: {errorInfo.componentStack}
</Text>
) : null}
</ScrollView>
</View>
</SafeAreaView>
)
}

return this.props.children
Expand Down

0 comments on commit f02f686

Please sign in to comment.