import React from 'react'; import { NativeModules, ViewStyle, StyleProp } from 'react-native'; import { MiniAppContext } from '../Context'; export interface ViewBoundaryProps { children: React.ReactNode; fallback?: React.ReactNode; fallbackStyle?: StyleProp; onError?: (error: Error, errorInfo: React.ErrorInfo) => void; } interface ViewBoundaryState { hasError: boolean; error: Error | null; } class ViewBoundary extends React.Component< ViewBoundaryProps, ViewBoundaryState > { static contextType = MiniAppContext; constructor(props: ViewBoundaryProps) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error: Error): ViewBoundaryState { return { hasError: true, error }; } componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { this.props.onError?.(error, errorInfo); const context = (this as any).context ?? {}; // check exist native module method onJSBoundaryCrash const nativeMethod = NativeModules?.MiniAppModule?.onJSBoundaryCrash; if (typeof nativeMethod === 'function') { try { nativeMethod({ hostId: context.hostId ?? '', appId: context.appId ?? '', code: context.code ?? '', buildNumber: context.buildNumber ?? '', tag: 'ViewBoundary', error: { errorName: error.name, errorMessage: error.message, componentStack: errorInfo?.componentStack?.substring(0, 500) ?? '', }, }); console.info('[ViewBoundary] onJSBoundaryCrash success!'); } catch (_e) { console.warn('[ViewBoundary] onJSBoundaryCrash failed:', _e); } } else { console.warn( '[ViewBoundary] onJSBoundaryCrash not available on this platform build', ); } } render() { if (this.state.hasError) { if (this.props.fallback !== undefined) { return this.props.fallback; } return null; } return this.props.children; } } export { ViewBoundary };