错误处理

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 回调函数)
  • 服务端渲染

results matching ""

    No results matching ""