Граница ошибки не обнаруживает ошибку от клиента 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
состояние уже выставлено на крючок для вас.