@xysfe/catch-react-error
Version:
react error boundaries
76 lines (68 loc) • 2.33 kB
JavaScript
import * as React from 'react'
import { Component, forwardRef } from 'react'
import DefaultErrorBoundary from './components/DefaultErrorBoundary'
import { is_server, isComponentClass, isReactMemo } from './utils/index'
const catchreacterror = (Boundary = DefaultErrorBoundary) => ((InnerComponent) => {
if (Boundary && !Boundary.prototype.isReactComponent) {
console.warn(`The ${Boundary} component is not a react component`);
Boundary = DefaultErrorBoundary
}
if (Boundary && !(Boundary.prototype.componentDidCatch || Boundary.prototype.getDerivedStateFromError)) {
console.warn(`${Boundary} doesn't has componentDidCatch or getDerivedStateFromError`);
Boundary = DefaultErrorBoundary
}
// 将React.memo包裹过的组件转换成普通函数式组件
if (!isComponentClass(InnerComponent) && isReactMemo(InnerComponent)) {
const NewComponent = InnerComponent;
InnerComponent = function (props) {
return <NewComponent {...props} />
}
}
if (isComponentClass(InnerComponent)) {
if (is_server()) {
const originalRender = InnerComponent.prototype.render
InnerComponent.prototype.render = function () {
try {
return originalRender.apply(this, arguments);
} catch (error) {
console.error(error)
return null
}
}
}
class WrapperComponent extends Component {
render() {
const {
forwardedRef,
} = this.props;
return (
<Boundary >
{isComponentClass(InnerComponent) ?
<InnerComponent {...this.props} ref={forwardedRef} /> :
<InnerComponent {...this.props} />
}
</Boundary>
)
}
}
return forwardRef((props, ref) => <WrapperComponent forwardedRef={ref} {...props} />)
} else {
if (is_server()) {
const originalFun = InnerComponent;
InnerComponent = function () {
try {
return originalFun.apply(null, arguments);
} catch (error) {
console.error(error)
return null
}
}
}
return (props) => (
<Boundary >
<InnerComponent {...props} />
</Boundary>
)
}
})
export default catchreacterror