先了解一下工作原理,不过在那之前先说一下 React 工作流程
React 工作流程
- render 阶段:render 组件、diff算法
- commit 阶段:渲染真实 DOM
ErrorBoundary 实现原理
ErrorBoundary 就是捕获 React 工作流程中的错误 —— 不在工作流程中的就捕获不到 —— 比如 事件回调
捕获错误
- 如果「render阶段」发生错误,会被捕获并执行handleError方法
- 如果「commit阶段」发生错误,会被捕获并执行captureCommitPhaseError方法。
处理错误
getDerivedStateFromError
此生命周期会在后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state 更新 state 使下一次渲染可以显降级 UI
注意
getDerivedStateFromError
() 会在渲染阶段调用,因此不允许出现副作用。 如遇此类情况,请改用componentDidCatch
()。
在捕获错误之后,会在 ErrorBoundary 组件中 触发更新:
this.setState(
getDerivedStateFromError.bind(null, error)
)
this.setState第一个参数,除了可以接收「新的状态」,也能接收「改变状态的函数」作为参数
componentDidCatch
此生命周期在后代组件抛出错误后被调用。 它接收两个参数:
- error —— 抛出的错误。
- info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息。
componentDidCatch() 会在“提交”阶段被调用,因此允许执行副作用。 它应该用于记录错误之类的情况:
this.setState的第二个参数,可以接收「回调函数」作为参数 这样可以保证应用更新立即触发
当捕获错误后,会在ErrorBoundary对应组件中触发类似如下更新:
this.setState(this.state, componentDidCatch.bind(this, error))
为什么Hook 没
看上面就能发现,他这个 非常依赖 类组件的 setState 方法中的回调特性
而函数组件中的 useState 没有这些回调特性
实现一个试试
类组件 和 函数组件 在源码层面的运行流程也有差异 所以肯定不能完全复现