我发现自己试图使用ErrorBoundary创建错误处理程序,但是经过几天和大量的耐心,我设法通过在后端调用API来捕获错误并将错误保存在数据库中。 / p>
注意:如果您有更好的解决方案,请评论此帖子。
首先:按照ReactJs documentation的说明创建您的ErrorBoundary组件,但要添加一些修改
一旦您输入ComponentDidCatch,ErrorBoundary直接发送到渲染器,它就不会经历React的另一个生命周期,然后,我们创建了另一个中间组件来调用API并能够安静地使用生命周期,但是添加了一个回调方法来通知errorBoundary错误已被通知,并重定向主视图或主视图。
首先:我的Errorboundary组件:
/**
* @desc Dependencias
*/
import React, { Component, Fragment } from 'react';
/**
* @desc Acciones
*/
import { saveError } from '../../actions/ErrorsActions';
/**
* @desc Componentes
*/
import Modal from '../Modal/ModalContainer';
import ErrorMessage from './errorMesage';
class ErrorBoundary extends Component {
/**
* @desc Constructor del componente.
*
* @param { Object } props
*
* @return { Void }
*/
constructor(props) {
super( props );
// Estado incial.
this.state = {
// Se encontro un error.
foundError: {
display : false,
message: null
}
};
}
/**
* @desc Ciclo de vida: Comienzo del montado del componente.
*
* @return { void }
*/
componentDidMount(){
// Global catch of unhandled Promise rejections:
global.onunhandledrejection = error => {
// Warning: when running in "remote debug" mode (JS environment is Chrome browser),
// this handler is called a second time by Bluebird with a custom "dom-event".
// We need to filter this case out:
if (error instanceof Error) {
// Alias
let { foundError } = this.state;
// Indice del split al stack.
let index = error.stack.indexOf(".");
// Asignamos el stack
foundError.display = true;
foundError.message = error.stack.substring( 0, index )
.trim()
.replace(/(\r\n|\n|\r)/gm, "");
// Actualizamos el estado con el error.
this.setState({ foundError })
}
};
}
/**
* @desc Detecta los errores no manipulados de la aplicación.
*
* @param { Object } error
* @param { Object } info
*
* @return { Void }
*/
componentDidCatch( error, info) {
// Alias
let { foundError } = this.state;
// Indice del split al stack.
let index = info.componentStack.indexOf("(");
// Mensaje del error
let message = error.message + " - " + info.componentStack.substring( 0, index ).trim();
// Asignamos el stack
foundError.display = true;
foundError.message = message;
// Actualizamos el estado con el error.
this.setState({ foundError })
}
/**
* @desc
*
* @return { void }
*/
async closeModal(){
// `enter code here`Alias
let { foundError } = this.state;
// Reiniciamos el estado del error.
foundError.display = false;
foundError.message = null;
// Actualizamos el estado
await this.setStateAsync({ foundError });
}
/**
* @desc Renderiza el componente.
*
* @return { * }
*/
render() {
// Alias
let { language, children } = this.props;
let { foundError } = this.state;
// Validamos si se debe mostrar el modal de crash.
if( !foundError.display )
return children;
else
// You can render any custom fallback UI
return ( <ErrorMessage { ...this.props }
onClose={ () => this.closeModal() }
stack={ foundError.stack }
message={ foundError.message } /> );
}
}
export default ErrorBoundary;
在渲染器中,我们检查是否存在错误,如果存在,则将其称为错误组件,如果没有,则返回子级。
在ErrorMessage组件中:
/**
* @desc Dependencias
*/
import React, { Component, Fragment } from 'react';
/**
* @desc Lenguaje
*/
import Lenguaje from '../../lenguage/es-ar.json';
/**
* @desc Acciones
*/
import { saveError } from '../../actions/ErrorsActions';
/**
* @desc Componentes
*/
import Modal from '../Modal/ModalContainer';
class ErrorMeesage extends Component {
/**
* @desc Constructor del componente.
*
* @param { Object } props
*
* @return { Void }
*/
constructor(props) {
super( props );
this.state = {
// Modal de crash.
modalCrash: {
display: true,
type: 'crash',
content: {
title: '',
body: '',
}
}
}
}
componentDidMount(){
// Lanzamos el almacenamiento del stack.
this.saveAudit();
}
/**
* @desc Permite el acceso asincronico al setState de react.
*
* @param { Object } state
*
* @return { Promise }
*/
setStateAsync( state ){
return new Promise( resolve => this.setState( state, () => {
resolve()
}))
}
/**
* @desc Envia para almacenar el stack de errores.
*
* @return { Promise<void> }
*/
async saveAudit(){
// Alias
let { history, country, message } = this.props;
// Datos.
let data = {
type: 'WEB',
subtype: 'ERROR',
details: message
};
// Solicitamos el guardado del error.
let response = saveError( country, data );
// Esperamos la solicitud se cumpla.
response.payload = await response.payload;
// Datos del modal.
let title = Lenguaje && Lenguaje.WAS_AN_ERROR,
body = Lenguaje.GENERAL_ERROR_CODE.replace('{0}', response.payload.data ),
callback = async () => {
await this.hideModalCrash();
// Redirección.
history.push('/home');
};
// Mostramos el modal de crash.
await this.showModalCrash( title, body, callback );
}
/**
* Muestra el modal de error.
*
* @param { String } title
* @param { String } body
*
* @return { Promise<Boolean> }
*/
async showModalCrash( title = '', body = '', callback = null){
// Alias
let { modalCrash } = this.state;
try{
// Asignamos los valores al modal.
modalCrash.display = true;
modalCrash.content.title = title;
modalCrash.content.body = body;
modalCrash.callback = typeof callback === "function" && callback;
// Actualizamos el estado interno.
this.setState({ modalCrash });
return true;
}catch( error ){
return false;
}
}
/**
* Oculta el modal de error.
*
* @return { Promise<Boolean> }
*/
async hideModalCrash(){
// Alias
let { modalCrash } = this.state;
try{
// Limpiamos el modal de eliminación.
modalCrash.display = false;
modalCrash.content.title = '';
modalCrash.content.body = '';
// Actualizamos el estado.
await this.setStateAsync({ modalCrash });
// El modal fue ocultado.
await this.props.onClose();
return true;
}catch( error ){
return false;
}
}
/**
* @desc Renderiza el componente.
*
* @return { * }
*/
render() {
// Alias
let { modalCrash } = this.state;
let { language } = this.props;
return(<Modal type="crash"
isWrapper
dataModal={ modalCrash }
language={ language }
handleClick={ () => typeof modalCrash.callback === "function" && modalCrash.callback() } />);
}
}
export default ErrorMessage;
在ErrorMessage组件中,我们调用API来保存错误,我们显示了通知用户的模式,然后在HideCrashModal中,我们有一个方法通知ErrorBoundary通知了错误:await this.props.onClose ();
有关如何实现此组件的示例:
<Route path="/home" render= { props =>
<ErrorBoundary { ...this.props }>
<Welcome history={ props.history } dispatch={ props.dispatch } />
</ErrorBoundary>
} />
现在,ComponentDidCatch无法捕获异步代码中的错误,但是我们用BlueBird替换了promise,我们可以使用在ErrorBoundary中捕获这些错误的方法,以便我们有一个集中的错误点,因此我们添加了全局变量。如果BlueBird错误处理程序以某种承诺检测到错误,它将以这种方式在ComponentDidMount生命周期中进行onunhandlerrejection。