Граница ошибки не обнаруживает ошибку от клиента apollo

Я пытаюсь отловить некоторые ошибки на верхнем уровне, чтобы показать самую красивую страницу ошибок в мире.

По какой-то причине я вижу, что мои узлы отключены, но 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-response-app.

Я ожидаю увидеть <h1>Had error</h1>; Я получаю экран необработанной ошибки CRA.

1 ответ

Решение

Из документов

Границы ошибок делать не перехватывать ошибки для:

  • Обработчики событий (подробнее)
  • Асинхронный код (например, обратные вызовы setTimeout или requestAnimationFrame)
  • Рендеринг на стороне сервера
  • Ошибки, возникающие в самой границе ошибки (а не в ее дочерних элементах)

Промисы являются асинхронными, поэтому отклоненные промисы не попадают в границы ошибок. На данный момент рекомендуемый, но несколько хакерский подход - выбросить ошибку внутриsetState. В функциональных компонентах вы можете использовать функцию set, возвращаемуюuseState крючок вместо setState:

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

Бросив внутрь useEffect тоже будет работать, но не внутри then или catchобратный вызов обещания. Вы также не можете сделатьuseEffect обратный звонок asyncфункция, потому что она не может вернуть обещание. Итак, мы застряли в использованииsetState.

Также обратите внимание, что на самом деле нет причин звонить client.queryнапрямую, особенно потому, что этот код не будет повторно отображать ваш пользовательский интерфейс при изменении кеша. Вы должны использоватьuseQuery и data состояние уже выставлено на крючок для вас.

Другие вопросы по тегам