React16:错误边界组件

React16:使用错误边界组件

Posted by wang chong on April 15, 2019

React16出现一个错误边界组件,它可以捕捉到子组件树中任何位置捕获到错误,并记录这个错误,展示降级的UI而不是让整个组件树崩溃。错误边界组件的捕获错误是渲染期间,在整个生命周期方法以其整个树的构造函数中发生的错误。

React16中错误组件一共除了两个生命周期,两个生命周期都可以捕获错误,只是作用有些不同。

错误捕获生命周期的特点

先说一下错误组件生命周期的特点:

  • 错误组件的生命周期只能在渲染中捕获,但在事件处理程序中不会捕获。
  • 也就是说生命周期只在render渲染阶才会触发。

生命周期

错误组件的生命周期一共有两个:

  • static getDerivedStateFromError()
  • componentDidCatch

生命周期的执行时机

整个生命周期的执行时机分为两个时机:

  1. 渲染阶段
  2. 提交阶段

渲染时机 生命周期执行时机的渲染时机表示组件正在渲染。这个时机执行的生命周期有componentWillMountrendercomponentWillUpdate

提交时机 生命周期执行时机的提交时机是表示组件已经渲染完成,正要把Dom元素提交到html文档中去。这个时机执行的生命周期有componetDidMountgetSnapshotBeforeUpdatecomponentDidUpdate

static getDerivedStateFromError()

这个生命周期是类组件的一个静态方法,这个生命周期会在后代组件抛出错误后被调用。

这个钩子函数把抛出的错误作为参数,并且返回一个对象用来更新state。

这个钩子函数在渲染时机调用,因此不允许出现副作用,是一个比较纯的函数。

static getDerivedStateFromError(error){
        return {
            hasError: true
        }
    }

componentDidCatch

componentDidCatch方法有两个参数。

  1. 第一个参数为err对象,表示错误信息。
  2. 第二个错误为info,为一个对象,对象中有一个属性componentStack,表示组件栈追踪,可以很快的找到出现错误的组件。

componentDidCatch() 会在“提交”阶段被调用,因此允许执行副作用。

注意点

这两个生命周期有优先级问题,即getDerivedStateFromError会比componentDidCatch先调用,如果getDerivedStateFromError中有返回值,则componentDidCatch不会调用。

getDerivedStateFromError不可以有副作用并且返回一个对象用于改变state,适用于作UI降级。

componentDidCatch中可以有副作用可以用于发送错误上报到错误服务器。

特别注意:这两个钩子函数不要在一起使用使用。

错误组件

捕获错误生命周期不建议直接在组件中使用,建议创建一个错误组件,可以把错误组件当作根组件用于捕获全局错误。

定义错误捕获组件

class ErrorBoundary extends Component {
    constructor(props){
        super(props);
        this.state = {hasError: false};
        this.err;
        this.info;
    }
    //捕获报错和报错上报程序库一起使用。
    componentDidCatch(err,info){
        this.err = err;
        this.info = info;
        this.setState({hasError: true});
    }
    render(){
         if(this.state.hasError){
            return (
                <>
                    <div >
                        <p>{this.err.message}</p>
                        <p>{this.info && this.info.componentStack}</p>
                    </div>
                    {this.props.children}
                </> 
            )
        }
        return this.props.children;
    }
}

定义子组件

class Profile extends Component {
    constructor(props){
        super(props);
        this.state = {
            todos:["hello"]
        };
    }
    chlickHandle(){
        this.setState({
            todos: undefined,
        })
    }
    render() {
        return (
            <>
                <button onClick={()=>this.chlickHandle()}>click</button>
                <span>用户名:{this.state.todos[0]}</span>
            </>
        )
    }
}

使用

export default class Greeting extends Component {
    render(){
        return (
            <ErrorBoundary>
                <Profile />
            </ErrorBoundary>
        )
    }
}

与插槽组件配合

React16同样也除了一个插槽组件,作用是把组件中的数据渲染到特定的Dom元素中。错误组件和插槽组件配合来使用就可以把错误信息渲染到指定的地方显示出来,用来提示用户,从而提高用体验。