React 中的错误边界:为什么“throw new Error('some message')”失败而 'throw errorObj' 有效?

Error Boundary in React: why does 'throw new Error('some message')' fail and 'throw errorObj' work?

我正在学习 React 中的错误边界。我想我已经有了很好的基本理解,但是在为异步进程(例如加载数据)实现它们时遇到了麻烦。

假设我有一个简单的组件,它使用 React 挂钩从远程 API 加载一些数据。由于错误边界本身不会使用异步进程工作,而不是在 catch 中抛出错误,此组件将 error 存储在 state 中并在下次重新渲染时抛出它

// MovieDb.js
import axios from "axios"
import {useEffect,useState} from 'react'

export default (query) => {

  const [movies, setMovies] = useState([])
  const [error,setError] = useState(null)

  if (error) throw error

  useEffect(() => {
    const getData = async () => {
      try {
        const results = await axios.get('https://api.themoviedb.org/3/search/movie', {
          params: {
            api_key: 'somethingsomething',
            query
          }
        })
        setMovies(results.data.results)
      } catch (e) {
       setError(e)
      }
    }
    getData()
  }, [query])

  return movies

}

这个组件在我的应用程序中使用:

// App.js
  function App() {

  const [query, setQuery] = useState('Lord of the Rings')

  const movies = MovieDb(query)
  return (
    <div className="App">
      <SearchInput onChange={e => setQuery(e.target.value)} defaultValue={query}/>
      {movies && movies.map(movie=> <div key={movie.id}>{movie.title}</div>) }
    </div>
  );
}

export default App;

我的错误边界很简单:

//Catch.js
import React, { Component } from 'react'

export default class Catch extends Component {
  state = { hasError: false ,error:''}

  static getDerivedStateFromError(error) {
    return { hasError: true,error }
  }

  render() {
    if (this.state.hasError) {

      return <h1>{`There was a problem: ${this.state.error.message}`}</h1>
    }

    return this.props.children
  }
}

Catch 组件然后包装应用程序:

// index.js
ReactDOM.render(<Catch><App/></Catch>, document.getElementById('root'));

当我在 MovieDb 中抛出错误时,例如调用 API 时,错误边界似乎起作用了。然而,当我改变

 if (error) throw error

 if (error) throw new Error('some message')

 if (error) throw new Error(error.message)

错误边界不起作用,应用程序崩溃。为什么是这样?我问这个问题是为了让我能更好地理解 我在做什么,而不仅仅是让它发挥作用。感谢您的帮助!

这是开发环境的产物。 您可以通过点击 "escape" 或 "X" 关闭堆栈跟踪来查看您的实际 UI。这不会出现在生产中。 我相信反应开发代码会查看抛出异常的位置,如果它在您的代码中,那么您会看到 UI.

参见: