)}
>
{children}
)
}
/**
* Using throwOnError with Queries
*
* Queries can throw errors to error boundaries
*/
import { useQuery } from '@tanstack/react-query'
// Example 1: Always throw errors
function UserData({ id }: { id: number }) {
const { data } = useQuery({
queryKey: ['user', id],
queryFn: async () => {
const response = await fetch(`/api/users/${id}`)
if (!response.ok) throw new Error('User not found')
return response.json()
},
throwOnError: true, // Throw to error boundary
})
return
{data.name}
}
// Example 2: Conditional throwing (only server errors)
function ConditionalErrorThrowing({ id }: { id: number }) {
const { data } = useQuery({
queryKey: ['user', id],
queryFn: async () => {
const response = await fetch(`/api/users/${id}`)
if (!response.ok) throw new Error(`HTTP ${response.status}`)
return response.json()
},
throwOnError: (error) => {
// Only throw 5xx server errors to boundary
// Handle 4xx client errors locally
return error.message.includes('5')
},
})
return
{data?.name ?? 'Not found'}
}
/**
* Multiple Error Boundaries (Layered)
*
* Place boundaries at different levels for granular error handling
*/
export function LayeredErrorBoundaries() {
return (
// App-level boundary
}>
{/* Feature-level boundary */}
}>
{/* Another feature boundary */}
)
}
/**
* Key concepts:
*
* 1. QueryErrorResetBoundary: Provides reset function for TanStack Query
* 2. throwOnError: Makes query throw errors to boundary
* 3. Layered boundaries: Isolate failures to specific features
* 4. Custom fallbacks: Control error UI per boundary
* 5. Error logging: componentDidCatch for monitoring
*
* Best practices:
* ✅ Always wrap app in error boundary
* ✅ Use throwOnError for critical errors only
* ✅ Provide helpful error messages to users
* ✅ Log errors to monitoring service
* ✅ Offer reset/retry functionality
* ❌ Don't catch all errors - use local error states when appropriate
* ❌ Don't throw for expected errors (404, validation)
*/