reactjsreact-queryreact-suspensereact-error-boundary

React - Error boundary not catching error


I have a component where I am fetching mock data. I am doing a query by using react-query with Suspense. I was following their docs. This is the component:

export const WorkHistory = () => {
    const { caseId } = useContext();
    const { api: mockApi } = useMockApi();
    const { data: workHistory } = mockApi.getWorkHistory(caseId.toString());

    return (
        <QueryErrorResetBoundary>
            {({ reset }) => (
                <ErrorBoundary
                    fallbackRender={({ error, resetErrorBoundary }) => (
                        <div>
                            There was an error! <Button onClick={() => resetErrorBoundary()}>Try again</Button>
                            <pre style={{ whiteSpace: "normal" }}>{error.message}</pre>
                        </div>
                    )}
                    onReset={reset}
                >
                    <Suspense
                        fallback={
                            <div className="flex justify-center">
                                <Loader size="3xlarge" title="Loading..." />
                            </div>
                        }
                    >
                        <WorkHistory workHistory={workHistory} />
                    </Suspense>
                </ErrorBoundary>
            )}
        </QueryErrorResetBoundary>
    );
};

And this is the getWorkHistory in mockApi:

const getWorkHistory = (caseId: string) =>
        useQuery({
            queryKey: `workHistory`,
            queryFn: (): Promise<WorkHistoryDto[]> => fakeFetch(JSON.parse(localStorage.getItem(`workHistory`))),
            staleTime: Infinity,
            suspense: true,
        });

const fakeFetch = (result): Promise<any> =>
        new Promise((resolve, reject) => {
            setTimeout(() => reject(new Error("fail")), 1000);
        });

But, this ErrorBoundary is not catching this error. I get this:

Uncaught Error: fail

What am I doing wrong here?


Solution

  • You are calling useQuery outside of the ErrorBoundary:

    export const WorkHistory = () => {
        // ⬇️ useQuery is called here
        const { data: workHistory } = mockApi.getWorkHistory(caseId.toString());
    
        return (
            <QueryErrorResetBoundary>
                {({ reset }) => (
                // ⬇️ your ErrorBoundary starts here
                    <ErrorBoundary
                      ...
                    </ErrorBoundary>
                )}
            </QueryErrorResetBoundary>
        );
    };
    

    The useQuery call is what throws the error to the nearest ErrorBoundary, so it has to be inside the ErrorBoundary, not above it.


    unrelated, but still important: You are violating the rules of hooks by calling useQuery inside a function called getWorkHistory. Hooks must be called in functional components or other hooks, so you would need to name that function useWorkHistory or useGetWorkHistory.