很多项目中,都需要收集线上错误信息。使用的方案也有很多,相关的第三方也有很多。大家可以自行查阅。本文针对其中的一种方式,分享一种比较简单的优化方案。
存在问题的方案:
利用componentDidCatch
方法,捕获错误并上报。
最简单粗暴的方法:
在整个项目入口组件内,实现componentDidCatch
方法,里面实现上报错误和记录日志的功能。
相关准备:
与后端约定好错误上报接口,并准备好相关方法。
实现:
componentDidCatch(error, info) {
this.setState({
error,
hasError: true,
});
// 上报给服务端并在本地写日志
ErrorUtils.uploadToServerAndWriteLocalLog(error, info);
}
render() {
const { hasError, error } = this.state;
if (hasError) {
return <ErrorView data={error} />
}
return <App />
}
弊端
项目内任何地方出现报错,整个项目都无法运行,因为错误都会冒泡到项目的入口文件,必须退出重新打开app才行。
改进方法
通过高阶组件的方式,可以让项目内各个页面分别抓取自己的错误,这样一旦某个页面报错,也仅仅是当前页面显示崩溃信息,退出当前页面,仍可以使用项目内其他功能。能优化产品体验
代码
封装高阶组件
import React, { Component } from 'react';
import * as ErrorUtil from './ErrorUtil';
import ErrorCatchView from './ErrorCatchView';
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
export default WrappedComponent => {
class ErrorCatchComponent extends Component {
constructor(props) {
super(props);
this.state = {
error: new Error(),
hasError: false,
};
}
componentDidCatch(error, info) {
this.setState({
error,
hasError: true,
});
ErrorUtil.uploadToServerAndWriteLocalLog(error, info);
}
render() {
const { hasError, error } = this.state;
if (hasError) {
return <ErrorCatchView content={error.toString()} />;
}
return <WrappedComponent {...this.props} />;
}
}
ErrorCatchComponent.displayName = `HOC${getDisplayName(WrappedComponent)}`;
return ErrorCatchComponent;
};
自定义崩溃页面,即一旦页面报错,就显示该页面,实际内容可根据项目需要自定义
import React, { PureComponent } from 'react';
import { Text, View, StyleSheet } from 'react-native';
type Props = {
content: String,
};
export default class ErrorCatchView extends PureComponent<Props> {
render() {
const { content } = this.props;
return (
<View style={styles.container}>
<Text>{content}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
错误上报模块, 实际根据项目需要自己实现即可
export function uploadToServerAndWriteLocalLog(error, info) {
uploadToServer(error, info);
writeLocalLog(error, info);
}
function uploadToServer(error, info) {}
function writeLocalLog(error, info) {}
使用方法
结合修饰器使用,每个需要补货错误的地方,添加@ErrorCatch
即可
@ErrorCatch
export default class Example extends PureComponent {
state = { num: 0 };
componentDidMount() {
this.load();
}
load = async () => {
const res = await this.requestData();
this.setState({ num: res });
};
requestData = () => {};
render() {
const { num } = this.state;
return (
<View>
<Text> textInComponent {num} </Text>
</View>
);
}
}
组件出现错误,都会显示预先自定义的错误页面。不影响项目其他部分。
项目入口的didCatch依然需要保留。这样子万一 errorCatch模块本身出错,仍旧可以捕获并上报。