错误处理
Nerv 和 React fiber 一样,支持使用 componentDidCatch
来处理组件中可能会发生的错误。
捕获组件内的错误
如下的代码在 Nerv 中使用是完全合法的:当 this.state.error
是一个假值(falsey) 时,render()
函数直接抛出异常——而这个异常会被当前组件的 componentDidCatch
捕捉到,这里使用的错误处理是把 this.state.error
设为真值。组件得以正常渲染。
class BrokenRender extends Component {
state = { error: null }
componentDidCatch(error) {
this.setState({ error })
}
render() {
if (this.state.error) {
return <span>{`Caught an error: ${this.state.error.message}.`}</span>
}
throw new Error('broken')
}
}
使用错误边界(ErrorBoundary)
如果当前组件没有设置 componentDidCatch
时,Nerv 会继续往它的父组件寻找设置了 componentDidCatch
的组件,并在该组件调用 componentDidCatch
方法处理错误。这意味着你可以设置一个错误边界(ErrorBoundary)组件来处理错误:
class ErrorBoundary extends Component {
state = { error: null }
componentDidCatch(error) {
this.setState({ error })
}
render() {
if (this.state.error) {
return <span>{`Caught an error: ${this.state.error.message}.`}</span>
}
return <div>{this.props.children}</div>
}
}
class BrokenRender extends Component {
componentDidMount() {
throw new Error('Hello')
}
render() {
return <span>Hello</span>
}
}
render(
<ErrorBoundary>
<BrokenRender />
</ErrorBoundary>,
scratch
)
在如上代码代码中,BrokenRender
并没有错误处理方法,但是它的父组件 ErrorBoundary
可以处理错误并打印错误信息。这意味着即便 BrokenRender
崩溃了,其他组件也能正常地运行。合理地使用 ErrorBoundary
将会很好地提高开发和用户体验。
为何不使用 try/catch?
try / catch
也可以做相同的事情,但其仅能在命令式代码(imperative code)下可用:
try {
showButton();
} catch (error) {
// ...
}
然而,Nerv 组件是声明式的并且具体指出 声明 什么需要被渲染:
<Button />
错误边界保留了 Nerv 原生的声明性质,且其行为符合你的预期。例如,即使错误发生 componentDidUpdate
时期由某一个深层组件树中的 setState
调用引起,其仍然能够冒泡到最近的错误边界。
componentDidCatch
无法处理的错误
- 事件处理
- 异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)
- 服务端渲染