From d20aaf2ffcc56bf90326743f045c138a20582de3 Mon Sep 17 00:00:00 2001 From: Niek Date: Sat, 12 Sep 2020 20:54:32 +0200 Subject: [PATCH] fix: useInfinityQuery fetchMore should not throw --- src/core/query.ts | 8 ++--- src/core/queryObserver.ts | 19 +++++----- src/core/utils.ts | 4 +-- src/react/tests/useInfiniteQuery.test.tsx | 44 ++++++++++++++++++++++- src/react/useBaseQuery.ts | 2 +- 5 files changed, 59 insertions(+), 18 deletions(-) diff --git a/src/core/query.ts b/src/core/query.ts index 96f66cdb96..a95ddd9129 100644 --- a/src/core/query.ts +++ b/src/core/query.ts @@ -296,7 +296,7 @@ export class Query { } } - async fetchMore( + fetchMore( fetchMoreVariable?: unknown, options?: FetchMoreOptions, config?: ResolvedQueryConfig @@ -380,7 +380,7 @@ export class Query { return this.promise } - private async startFetch( + private startFetch( config: ResolvedQueryConfig, params: unknown[], _options?: FetchOptions @@ -397,7 +397,7 @@ export class Query { return this.tryFetchData(config, fetchData) } - private async startInfiniteFetch( + private startInfiniteFetch( config: ResolvedQueryConfig, params: unknown[], options?: FetchOptions @@ -455,7 +455,7 @@ export class Query { return this.tryFetchData(config, fetchData) } - private async tryFetchData( + private tryFetchData( config: ResolvedQueryConfig, fn: QueryFunction ): Promise { diff --git a/src/core/queryObserver.ts b/src/core/queryObserver.ts index 13c1f109d3..d3a062bdb7 100644 --- a/src/core/queryObserver.ts +++ b/src/core/queryObserver.ts @@ -1,8 +1,9 @@ import { getStatusProps, - isServer, isDocumentVisible, + isServer, isValidTimeout, + noop, } from './utils' import type { QueryResult, ResolvedQueryConfig } from './types' import type { Query, Action, FetchMoreOptions, RefetchOptions } from './query' @@ -108,23 +109,21 @@ export class QueryObserver { return this.currentQuery.clear() } - async refetch(options?: RefetchOptions): Promise { + refetch(options?: RefetchOptions): Promise { return this.currentQuery.refetch(options, this.config) } - async fetchMore( + fetchMore( fetchMoreVariable?: unknown, options?: FetchMoreOptions ): Promise { - return this.currentQuery.fetchMore(fetchMoreVariable, options, this.config) + return this.currentQuery + .fetchMore(fetchMoreVariable, options, this.config) + .catch(noop) } - async fetch(): Promise { - try { - return await this.currentQuery.fetch(undefined, this.config) - } catch { - // ignore - } + fetch(): Promise { + return this.currentQuery.fetch(undefined, this.config).catch(noop) } private optionalFetch(): void { diff --git a/src/core/utils.ts b/src/core/utils.ts index c10e536319..7875894a1c 100644 --- a/src/core/utils.ts +++ b/src/core/utils.ts @@ -36,8 +36,8 @@ export function uid(): number { export const isServer = typeof window === 'undefined' -export function noop(): void { - return void 0 +export function noop(): undefined { + return undefined } export let Console: ConsoleObject = console || { diff --git a/src/react/tests/useInfiniteQuery.test.tsx b/src/react/tests/useInfiniteQuery.test.tsx index e5155c1018..a85f536d70 100644 --- a/src/react/tests/useInfiniteQuery.test.tsx +++ b/src/react/tests/useInfiniteQuery.test.tsx @@ -1,7 +1,7 @@ import { render, waitFor, fireEvent } from '@testing-library/react' import * as React from 'react' -import { sleep, queryKey, waitForMs } from './utils' +import { sleep, queryKey, waitForMs, mockConsoleError } from './utils' import { useInfiniteQuery, useQueryCache } from '..' import { InfiniteQueryResult } from '../../core' @@ -112,6 +112,48 @@ describe('useInfiniteQuery', () => { }) }) + it('should not throw when fetchMore returns an error', async () => { + const consoleMock = mockConsoleError() + const key = queryKey() + let noThrow: boolean + + function Page() { + const start = 1 + const state = useInfiniteQuery( + key, + async (_key, page: number = start) => { + if (page === 2) { + throw new Error('error') + } + return page + }, + { + retry: 1, + retryDelay: 10, + getFetchMore: (lastPage, _pages) => lastPage + 1, + } + ) + + const { fetchMore } = state + + React.useEffect(() => { + setTimeout(async () => { + try { + await fetchMore() + noThrow = true + } catch (error) {} + }, 20) + }, [fetchMore]) + + return null + } + + render() + + await waitFor(() => expect(noThrow).toBe(true)) + consoleMock.mockRestore() + }) + it('should keep the previous data when keepPreviousData is set', async () => { const key = queryKey() const states: InfiniteQueryResult[] = [] diff --git a/src/react/useBaseQuery.ts b/src/react/useBaseQuery.ts index cce86a709d..b811824812 100644 --- a/src/react/useBaseQuery.ts +++ b/src/react/useBaseQuery.ts @@ -5,7 +5,7 @@ import { getResolvedQueryConfig } from '../core/config' import { QueryObserver } from '../core/queryObserver' import { QueryResultBase, QueryKey, QueryConfig } from '../core/types' import { useErrorResetBoundary } from './ReactQueryErrorResetBoundary' -import { useQueryCache } from '.' +import { useQueryCache } from './ReactQueryCacheProvider' import { useContextConfig } from './ReactQueryConfigProvider' export function useBaseQuery(