详细的介绍请看这里
部分 UI 的异常不应该破坏了整个应用。为了解决 React 用户的这一问题,React 16 引入了一种称为 “错误边界” 的新概念。 错误边界是用于捕获其子组件树 JavaScript 异常,记录错误并展示一个回退的 UI 的 React 组件,而不是整个组件树的异常。错误组件在渲染期间,生命周期方法内,以及整个组件树构造函数内捕获错误。
⚠️⚠️⚠️⚠️⚠️
- 事件处理 (比如调用了一个不存在的方法
this.abc()
,并不会执行componentDidCatch
)- 异步代码 (例如
setTimeout
或requestAnimationFrame
回调函数)- 服务端渲染
- 错误边界自身抛出来的错误 (而不是其子组件)
⚠️⚠️⚠️⚠️⚠️当render()函数出现问题时,componentDidCatch
会捕获异常并处理
此时,render()函数里面发生错误,则 componentDidCatch 会进行调用,在里面进行相应的处理
render() {
let a = [1,2,3]
let value = a[3].toString() 对 undefined 进行操作
return (......)
}
防止 页面 级别的崩溃~
防止 页面 级别的崩溃~
防止 页面 级别的崩溃~
使用方式一:组件方式
/*
* 当做组件使用
* */
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
};
}
componentDidCatch(error, info) {
alert('1111')
this.setState({
error
});
// 设置崩溃以后显示的UI
// 上传错误日志
}
render() {
if (this.state.error) { // 如果页面崩溃,则显示下面的UI
return (
<View style={{justifyContent: 'center', alignItems: 'center'}}>
<Text style={{color: 'red'}}>
{this.state.error && this.state.error.toString()}
</Text>
</View>
);
}
return this.props.children;
}
}
class RNTestPage extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
}
this.onPress = this.onPress.bind(this);
}
onPress(){
let newCount = this.state.count + 1
this.setState({
count: newCount
},()=>{
if (this.state.count == 5){
throw new Error('i crashed!!!')
}
})
}
render() {
// let a = [1,2,3]
// let value = a[3].toString()
return (
<ErrorBoundary>
<View style={styles.container}>
<TouchableOpacity onPress={this.onPress}>
<Text>点击我,第5次就崩溃啦</Text>
</TouchableOpacity>
<Text style={styles.text}>正常页面显示</Text>
</View>
</ErrorBoundary>
)
}
}
export default class RNTest extends React.Component {
render() {
return (
<ErrorBoundary>
<RNTestPage />
</ErrorBoundary>
)
}
}
使用方式二:高阶组件方式
高阶组件
import React from 'react'
import {
View,
Text
} from 'react-native'
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
export default (WrappedComponent)=> {
class Component extends React.Component {
constructor(props){
super(props)
this.state = {
error: new Error(),
hasError: false // UI级代码是否崩溃
}
}
componentDidCatch(error, info){
this.setState({
error,
hasError: true
})
}
render() {
if (this.state.hasError){
return <View>
<Text>
{this.state.error.toString()}
</Text>
</View>
}
return <WrappedComponent {...this.props}/>
}
}
Component.displayName = `HOC(${getDisplayName(WrappedComponent)})`;
return Component
}
使用
/*
* 高阶组件方式使用
* */
@HocErrorCatch
export default class RNTestPage extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
}
this.onPress = this.onPress.bind(this);
}
onPress(){
let newCount = this.state.count + 1
this.setState({
count: newCount
},()=>{
if (this.state.count == 5){
throw new Error('i crashed!!!')
}
})
}
render() {
// let a = [1,2,3]
// let value = a[3].toString()
return (
<View style={styles.container}>
<TouchableOpacity onPress={this.onPress}>
<Text>点击我,第5次就崩溃啦</Text>
</TouchableOpacity>
<Text style={styles.text}>正常页面显示</Text>
</View>
)
}
}
推荐使用高阶组件方式~