错误边界无法捕获来自Apollo客户端的错误

时间:2020-02-19 10:58:19

标签: reactjs error-handling apollo react-error-boundary

我正在尝试在顶层捕获一些错误,以显示世界上最漂亮的错误页面。

由于某种原因,我看到我的节点断开了连接,但是错误边界从未触发。

import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
import ApolloClient, { gql } from 'apollo-boost';

const client = new ApolloClient({ uri: "/graphql" });
const query = gql`{ items { id }}`;

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError(error: any) {
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      return <h1>Had error</h1>
    } else {
      return this.props.children;
    }
  }
}

function App() {
  const [data, setData] = useState<any>(null);

  useEffect(() => {
    client.query({ query })
      .then(res => setData(res))
      .catch(err => { console.warn("Error:", err); throw err; });
  }, []);

  return <pre>Data: {data}</pre>;
}

ReactDOM.render(
  <ErrorBoundary>
      <App />
  </ErrorBoundary>,
  document.getElementById('root')
);

我在一个空的create-react-app项目中运行它。

我希望看到<h1>Had error</h1>;我得到CRA未处理的错误屏幕。

1 个答案:

答案 0 :(得分:0)

docs

错误边界不会捕获以下错误:

  • 事件处理程序(了解更多)
  • 异步代码(例如setTimeout或requestAnimationFrame回调)
  • 服务器端渲染
  • 错误边界本身(而不是其子级)引发的错误

Promise是异步的,因此被拒绝的Promise不会被错误边界捕获。目前,recommended but somewhat hackish approach会将错误抛出到setState中。在功能组件中,可以使用useState钩子返回的set函数代替setState

const [, setState] = useState()
useEffect(() => {
  client.query({ query })
    .then(res => setData(res))
    .catch(err => {
      console.warn("Error:", err);
      setState(() => {
        throw err;
      });
    });
}, []);

useEffect内进行抛出也可以,但是在Promise的thencatch回调中则无效。您也无法将useEffect回调设为async函数,因为它无法返回Promise。因此,我们坚持使用setState

还要注意,实际上没有理由直接调用client.query,特别是因为如果缓存发生更改,此代码将重新呈现您的UI。您应该使用useQuery和该钩子已经暴露的data状态。