当前位置: 首页 > 科技观察

ErrorBoundaries就是这样实现的,还是蛮巧妙的

时间:2023-03-11 22:28:44 科技观察

大家好,我是Kason。本文将讲解React中ErrorBoundaries的完整实现逻辑。一张图总结:这里简单介绍一下React的工作流程,后面会有用。分为三步:触发更新渲染阶段:计算更新带来的副作用提交阶段:在宿主环境中执行副作用副作用有很多,比如:插入DOM节点执行useEffect回调OK,我们进入正题.什么是ErrorBoundariesReact提供了两个与“错误处理”相关的API:getDerivedStateFromError:静态方法,提供在错误发生时渲染回退UI的机会componentDidCatch:组件实例方法,提供在错误发生时记录错误信息的机会ClassComponent这两个API通常称为ErrorBoundaries(错误边界)。ErrorBoundaries的“后代组件”中发生的所有“React工作流”错误都将被ErrorBoundaries捕获。从一开始的介绍我们可以知道,“React工作流”指的是render阶段的commit阶段的代码:classErrorBoundaryextendsComponent{componentDidCatch(e){console.warn("Anerroroccurred",e);}render(){return

{this.props.children}
;}}constApp=()=>()A、B、C作为组件的ErrorBoundary后代,当“在React工作流中”发生错误时,会被ErrorBoundary中的componentDidCatch方法捕获。第1步:捕获错误首先看“何时捕获工作流中的错误”。render阶段的核心代码如下,发生的错误会由handleError处理:do{try{//对于并发更新,是workLoopConcurrentworkLoopSync();break;}catch(thrownValue){handleError(root,thrownValue);}}while(真);commit阶段包括很多工作,比如:componentDidMount/Update执行绑定/解绑refuseEffect/useLayoutEffect回调和destroy执行这些任务会以如下形式执行,发生的错误由captureCommitPhaseError处理:try{//...执行某事Work}catch(error){captureCommitPhaseError(fiber,fiber.return,error);}第2步:构造回调。可以发现,即使没有ErrorBoundaries,“工作流”中的错误也已经被React捕捉到了。正确的逻辑应该是:如果存在ErrorBoundaries,则执行相应的API,并抛出React的提示信息;如果没有错误边界,抛出一个“未捕获的错误”。因此,无论是handleError还是captureCommitPhaseError,都会从发生错误的节点的父节点开始,逐层向上遍历,寻找最近的ErrorBoundaries。一旦找到,就会构造:callbackfor"executingErrorBoundariesAPI"callbackfor"throwReactpromptinformation"React错误信息,包括提示和错误栈//...为了可读性,逻辑有一个删除函数createClassErrorUpdate(){if(typeofgetDerivedStateFromError==='function'){//用于执行getDerivedStateFromError=()=>{returngetDerivedStateFromError(error);}的callbackupdate.payload;};//用于抛出React提示信息callbackupdate.callback=()=>{logCapturedError(fiber,errorInfo);};}if(inst!==null&&typeofinst.componentDidCatch==='function'){//执行componentDidCatch=functioncallback(){this.componentDidCatch(error);};}的Callbackupdate.callbackreturnupdate;}如果没有找到ErrorBoundaries,继续向上遍历到根节点。这个时候会构造:callbackfor"throwinguncaughterrors"callbackfor"throwingReactpromptinformation"//...为了可读性,删除了逻辑funffctioncreateRootErrorUpdate(){//forthrowcallbackupdate.callback=()=>{onUncaughtError(error);logCapturedError(fiber,errorInfo);};returnupdate;}执行构造的回调时执行回调Execution?在React中,有两种“执行用户自定义回调”的API:对于ClassComponent,this.setState(newState,callback)中的newState和callback参数都可以将Function作为回调传递。所以,对于ErrorBoundaries来说,相当于active触发了一个更新:this.setState(()=>{//callbackusedtoexecutegetDerivedStateFromError},()=>{//callbackusedtoexecutecomponentDidCatch//andcallback用于抛出React提示信息})对于根节点,执行ReactDOM.render(element,container,callback)中的callback参数可以传递Function作为回调。因此,对于“没有ErrorBoundaries”的情况,相当于主动执行了如下函数:ReactDOM.render(element,container,()=>{//用于抛出“未捕获的错误”和“React提示信息”的回调})因此,ErrorBoundaries的实现可以看作是:React利用了现有API实现的新功能。总结经常有人问:为什么Hooks没有ErrorBoundaries?可以看出ErrorBoundaries的实现使用了this.setState可以传递回调的特性,useState暂时还不能完全对标。最后,留个作业给你。在官方文档[1]中,有4种情况的错误不会被ErrorBoundaries捕捉到。运用这篇文章的知识,你能分析出为什么他们没有被抓到吗?参考[1]官方文档:https://reactjs.org/docs/error-boundaries.html#introducing-error-boundaries