import * as React from 'react' ; type FallbackElement = React . ReactElement < unknown , string | React . FC | typeof React . Component > | null ; export interface FallbackProps { error : Error ; resetErrorBoundary : ( ) => void ; } export declare function FallbackRender ( props ) ; interface ErrorBoundaryProps { fallback ? : FallbackElement ; FallbackComponent ? : React . ComponentType < FallbackProps > ; fallbackRender ? : typeof FallbackRender ; onError ? : ( error : Error , info : string ) => void ; onReset ? : ( ) => void ; resetKeys ? : Array < unknown > ; onResetKeysChange ? : ( prevResetKey : Array < unknown > | undefined , resetKeys : Array < unknown > | undefined ) => void ; } interface ErrorBoundaryState { error : Error | null ; } const changedArray = ( a = [ ] , b = [ ] ) => { return a . length !== b . length || a . some ( ( item , index ) => ! Object . is ( item , b [ index ] ) ) ; } ; const initialState = { error : null , } ; class ErrorBoundary extends React . Component < React . PropsWithChildren < ErrorBoundaryProps > , ErrorBoundaryState > { state = initialState ; updatedWithError = false ; static getDerivedStateFromError ( error ) { return { error } ; } componentDidCatch ( error , errorInfo ) { if ( this . props . onError ) { this . props . onError ( error , errorInfo . componentStack ) ; } } componentDidUpdate ( prevProps ) { const { error } = this . state ; const { resetKeys , onResetKeysChange } = this . props ; if ( error !== null && ! this . updatedWithError ) { this . updatedWithError = true ; return ; } if ( error !== null && changedArray ( prevProps . resetKeys , resetKeys ) ) { if ( onResetKeysChange ) { onResetKeysChange ( prevProps . resetKeys , resetKeys ) ; } this . reset ( ) ; } } reset = ( ) => { this . updatedWithError = false ; this . setState ( initialState ) ; } ; resetErrorBoundary = ( ) => { if ( this . props . onReset ) { this . props . onReset ( ) ; } this . reset ( ) ; } ; render ( ) { const { fallback , FallbackComponent , fallbackRender } = this . props ; const { error } = this . state ; if ( error !== null ) { const fallbackProps = { error , resetErrorBoundary : this . resetErrorBoundary , } ; if ( React . isValidElement ( fallback ) ) { return fallback ; } if ( typeof fallbackRender === 'function' ) { return ( fallbackRender as typeof FallbackRender ) ( fallbackProps ) ; } if ( FallbackComponent ) { return < FallbackComponent { ... fallbackProps } / > ; } throw new Error ( 'ErrorBoundary 组件需要传入 fallback, fallbackRender, FallbackComponent 其中一个' ) ; } return this . props . children ; } } param Component param errorBoundaryProps function withErrorBoundary < P > ( Component , errorBoundaryProps ) { const Wrapped = props => { return ( < ErrorBoundary { ... errorBoundaryProps } > < Component { ... props } / > < /ErrorBoundary>); } ; const name = Component . displayName || Component . name || 'Unknown' ; Wrapped . displayName = `withErrorBoundary(${ name })` ; return Wrapped ; } param givenError function useErrorHandler < P = Error > ( givenError ? ) { const [ error , setError ] = React . useState < P | null > ( null ) ; if ( givenError ) throw givenError ; if ( error ) throw error ; return setError ; } export { ErrorBoundary , withErrorBoundary , useErrorHandler , } ;