【问题标题】:Error boundary doesn't catch error from apollo client错误边界不会从 apollo 客户端捕获错误
【发布时间】:2020-06-03 12:45:13
【问题描述】:

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

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

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 项目中运行它。

我希望看到&lt;h1&gt;Had error&lt;/h1&gt;;我收到 CRA 未处理的错误屏幕。

【问题讨论】:

  • 错误边界只会在生产版本中显示。您如何通过测试看到自己的界限?
  • 错误边界绝对适用于任何地方。只有调试错误覆盖没有在生产中显示。我通过使用 yarn start 运行 cra 来测试它(然后我从反应中看到调试窗口),并在生产中使用 yarn build && npx serve build (显示带有“数据:”字符串的窗口(所以 hasError 永远不会去真的)

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


【解决方案1】:

来自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 状态。

【讨论】:

  • 感谢您的回答!那行得通。关于useQuery,这个例子是一个最小的复制案例,在现实世界中它是一个加载事件数据的查询,所以很遗憾使用useQuery不起作用。
  • @yhaskell 明白了。您可能要考虑使用 useLazyQuery 代替。此外,虽然我想通过相同的机制处理所有错误,但您可能会考虑添加一个 ErrorLink 来为 Apollo 客户端进行全局错误处理,并将错误边界用于其他所有内容。即使有一些重复,它仍然可能整体上更干净。只是一个建议。
猜你喜欢
  • 2022-09-29
  • 2022-12-29
  • 2021-11-18
  • 2018-09-03
  • 1970-01-01
  • 2022-08-02
  • 2019-10-05
  • 1970-01-01
  • 2021-10-12
相关资源
最近更新 更多