React 异常处理

单页面应用的异常处理, React Boundary可以让我们对局部组件进行异常处理但仍保持其他组件的正常运行

React

React 异常处理

目录

1. Error Boundaries 组件

官方文档: Only class components can be error boundaries.

在没有 Error Boundaries 之前, 如果某个组件扔出了错误, 则整个项目都会被影响.

但 Error Boundary 只有其子组件(child component tree)才会 catch 到异常, 而不会影响到其它组件的渲染.

例如下面在App组件中渲染的Live2DWidget组件(一个看板娘), 如果Live2DWidget由于某些原因出现异常, 我们更希望保持其他的 UI 例如<Navbar />而不是整个页面白掉.

import React, { useState, useEffect, Component } from "react"

// 看板娘组件
const Live2DWidget = () => {
  const [status, setStatus] = useState("NORMAL")

  // 当status 不为NORMAL状态时 扔出异常
  if (status !== "NORMAL") {
    throw new Error("Error: 看板娘错误")
  }
  return (
    <>
      <h1> (。・∀・)ノ゙嗨</h1>
      <button onClick={() => setStatus("OFFLINE")}>点我</button> {/* 测试点击用 */}
    </>
  )
}

// 边界错误组件 可以用props来传递渲染的组件
class ErrorBoundary extends Component {
  constructor(props) {
    super(props)
    this.state = {
      error: null,
      errorInfo: null,
    }
  }

  componentDidCatch(error, errorInfo) {
    this.setState({
      error: error,
      errorInfo: errorInfo,
    })
  }

  render() {
    // 返回的UI
    if (this.state.errorInfo) {
      return this.props.display // 渲染异常展示组件
    }
    return this.props.children // 无异常则渲染原组件
  }
}

// 错误面板组件.
const ErrorModal = props => {
  return (
    <>
      <h1>{props.message}</h1>
      <button>关闭</button>
    </>
  )
}

const App = () => {
  return (
    <>
      <h1>Welcome back!</h1>
      <ErrorBoundary display={<ErrorModal message="看板娘错误" />}>
        <Live2DWidget />
      </ErrorBoundary>
    </>
  )
}

export default App

总结

  1. ErrorBoundary 必须是 class-components
  2. 如果异常则返回 fallback 的 UI
  3. ErrorBoundary 只是负责 catch 且逻辑相同, 因此可以用 props 来传递 fallback 的 UI 而不是创建多个不同的 Error Boundary 组件
  4. 异常只针对 child component tree, 对其他 UI 没影响

2. Event Handler

事件异常则可直接用try / catch处理.

const App = () => {
  const [error, setError] = useState(false)

  const handleEditProfile = () => {
    try {
      // POST
    } catch (err) {
      setError(err)
      console.log(err)
    }
  }

  return (
    <>
      {error && <ErrorModal />}
      <h1>User info</h1>
      <button onClick={handleEditProfile}>Edit Profile</button>
    </>
  )
}