Skip to content

Commit

Permalink
feat(query-core): Expose retry error as failureReason (#4315)
Browse files Browse the repository at this point in the history
* feat(query-core): Expose retry error as `failureReason`

* feat: Add `failureReason` to mutation as well

* fix: mutation `failureCount` not being reset to `0` on success

* chore: Add tests for mutation loading state reset

* fix: linting + tests
  • Loading branch information
Kuirak authored Oct 22, 2022
1 parent d026e41 commit 07c9631
Show file tree
Hide file tree
Showing 14 changed files with 279 additions and 33 deletions.
10 changes: 10 additions & 0 deletions docs/reference/useMutation.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const {
isLoading,
isPaused,
isSuccess,
failureCount,
failureReason,
mutate,
mutateAsync,
reset,
Expand Down Expand Up @@ -129,3 +131,11 @@ mutate(variables, {
- The error object for the query, if an error was encountered.
- `reset: () => void`
- A function to clean the mutation internal state (i.e., it resets the mutation to its initial state).
- `failureCount: number`
- The failure count for the mutation.
- Incremented every time the mutation fails.
- Reset to `0` when the mutation succeeds.
- `failureReason: null | TError`
- The failure reason for the mutation retry.
- Reset to `null` when the mutation succeeds.

4 changes: 4 additions & 0 deletions docs/reference/useQuery.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const {
error,
errorUpdatedAt,
failureCount,
failureReason,
isError,
isFetched,
isFetchedAfterMount,
Expand Down Expand Up @@ -251,6 +252,9 @@ const result = useQuery({
- The failure count for the query.
- Incremented every time the query fails.
- Reset to `0` when the query succeeds.
- `failureReason: null | TError`
- The failure reason for the query retry.
- Reset to `null` when the query succeeds.
- `errorUpdateCount: number`
- The sum of all errors.
- `refetch: (options: { throwOnError: boolean, cancelRefetch: boolean }) => Promise<UseQueryResult>`
Expand Down
20 changes: 15 additions & 5 deletions packages/query-core/src/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@ export interface MutationState<
data: TData | undefined
error: TError | null
failureCount: number
failureReason: TError | null
isPaused: boolean
status: MutationStatus
variables: TVariables | undefined
}

interface FailedAction {
interface FailedAction<TError> {
type: 'failed'
failureCount: number
error: TError | null
}

interface LoadingAction<TVariables, TContext> {
Expand Down Expand Up @@ -71,7 +74,7 @@ interface SetStateAction<TData, TError, TVariables, TContext> {
export type Action<TData, TError, TVariables, TContext> =
| ContinueAction
| ErrorAction<TError>
| FailedAction
| FailedAction<TError>
| LoadingAction<TVariables, TContext>
| PauseAction
| SetStateAction<TData, TError, TVariables, TContext>
Expand Down Expand Up @@ -171,8 +174,8 @@ export class Mutation<
}
return this.options.mutationFn(this.state.variables!)
},
onFail: () => {
this.dispatch({ type: 'failed' })
onFail: (failureCount, error) => {
this.dispatch({ type: 'failed', failureCount, error })
},
onPause: () => {
this.dispatch({ type: 'pause' })
Expand Down Expand Up @@ -272,7 +275,8 @@ export class Mutation<
case 'failed':
return {
...state,
failureCount: state.failureCount + 1,
failureCount: action.failureCount,
failureReason: action.error,
}
case 'pause':
return {
Expand All @@ -289,6 +293,8 @@ export class Mutation<
...state,
context: action.context,
data: undefined,
failureCount: 0,
failureReason: null,
error: null,
isPaused: !canFetch(this.options.networkMode),
status: 'loading',
Expand All @@ -298,6 +304,8 @@ export class Mutation<
return {
...state,
data: action.data,
failureCount: 0,
failureReason: null,
error: null,
status: 'success',
isPaused: false,
Expand All @@ -308,6 +316,7 @@ export class Mutation<
data: undefined,
error: action.error,
failureCount: state.failureCount + 1,
failureReason: action.error,
isPaused: false,
status: 'error',
}
Expand Down Expand Up @@ -344,6 +353,7 @@ export function getDefaultState<
data: undefined,
error: null,
failureCount: 0,
failureReason: null,
isPaused: false,
status: 'idle',
variables: undefined,
Expand Down
18 changes: 13 additions & 5 deletions packages/query-core/src/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export interface QueryState<TData = unknown, TError = unknown> {
errorUpdateCount: number
errorUpdatedAt: number
fetchFailureCount: number
fetchFailureReason: TError | null
fetchMeta: any
isInvalidated: boolean
status: QueryStatus
Expand Down Expand Up @@ -82,8 +83,10 @@ export interface FetchOptions {
meta?: any
}

interface FailedAction {
interface FailedAction<TError> {
type: 'failed'
failureCount: number
error: TError
}

interface FetchAction {
Expand Down Expand Up @@ -124,7 +127,7 @@ interface SetStateAction<TData, TError> {
export type Action<TData, TError> =
| ContinueAction
| ErrorAction<TError>
| FailedAction
| FailedAction<TError>
| FetchAction
| InvalidateAction
| PauseAction
Expand Down Expand Up @@ -473,8 +476,8 @@ export class Query<
this.isFetchingOptimistic = false
},
onError,
onFail: () => {
this.dispatch({ type: 'failed' })
onFail: (failureCount, error) => {
this.dispatch({ type: 'failed', failureCount, error })
},
onPause: () => {
this.dispatch({ type: 'pause' })
Expand All @@ -500,7 +503,8 @@ export class Query<
case 'failed':
return {
...state,
fetchFailureCount: state.fetchFailureCount + 1,
fetchFailureCount: action.failureCount,
fetchFailureReason: action.error,
}
case 'pause':
return {
Expand All @@ -516,6 +520,7 @@ export class Query<
return {
...state,
fetchFailureCount: 0,
fetchFailureReason: null,
fetchMeta: action.meta ?? null,
fetchStatus: canFetch(this.options.networkMode)
? 'fetching'
Expand All @@ -537,6 +542,7 @@ export class Query<
...(!action.manual && {
fetchStatus: 'idle',
fetchFailureCount: 0,
fetchFailureReason: null,
}),
}
case 'error':
Expand All @@ -552,6 +558,7 @@ export class Query<
errorUpdateCount: state.errorUpdateCount + 1,
errorUpdatedAt: Date.now(),
fetchFailureCount: state.fetchFailureCount + 1,
fetchFailureReason: error as TError,
fetchStatus: 'idle',
status: 'error',
}
Expand Down Expand Up @@ -611,6 +618,7 @@ function getDefaultState<
errorUpdateCount: 0,
errorUpdatedAt: 0,
fetchFailureCount: 0,
fetchFailureReason: null,
fetchMeta: null,
isInvalidated: false,
status: hasData ? 'success' : 'loading',
Expand Down
1 change: 1 addition & 0 deletions packages/query-core/src/queryObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ export class QueryObserver<
error,
errorUpdatedAt,
failureCount: state.fetchFailureCount,
failureReason: state.fetchFailureReason,
errorUpdateCount: state.errorUpdateCount,
isFetched: state.dataUpdateCount > 0 || state.errorUpdateCount > 0,
isFetchedAfterMount:
Expand Down
14 changes: 13 additions & 1 deletion packages/query-core/src/tests/mutations.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ describe('mutations', () => {
data: undefined,
error: null,
failureCount: 0,
failureReason: null,
isError: false,
isIdle: true,
isLoading: false,
Expand All @@ -97,6 +98,7 @@ describe('mutations', () => {
data: undefined,
error: null,
failureCount: 0,
failureReason: null,
isError: false,
isIdle: false,
isLoading: true,
Expand All @@ -115,6 +117,7 @@ describe('mutations', () => {
data: undefined,
error: null,
failureCount: 0,
failureReason: null,
isError: false,
isIdle: false,
isLoading: true,
Expand All @@ -133,6 +136,7 @@ describe('mutations', () => {
data: 'todo',
error: null,
failureCount: 0,
failureReason: null,
isError: false,
isIdle: false,
isLoading: false,
Expand Down Expand Up @@ -172,6 +176,7 @@ describe('mutations', () => {
data: undefined,
error: null,
failureCount: 0,
failureReason: null,
isError: false,
isIdle: false,
isLoading: true,
Expand All @@ -190,6 +195,7 @@ describe('mutations', () => {
data: undefined,
error: null,
failureCount: 0,
failureReason: null,
isError: false,
isIdle: false,
isLoading: true,
Expand All @@ -208,6 +214,7 @@ describe('mutations', () => {
data: undefined,
error: null,
failureCount: 1,
failureReason: 'err',
isError: false,
isIdle: false,
isLoading: true,
Expand All @@ -226,6 +233,7 @@ describe('mutations', () => {
data: undefined,
error: 'err',
failureCount: 2,
failureReason: 'err',
isError: true,
isIdle: false,
isLoading: false,
Expand Down Expand Up @@ -264,6 +272,7 @@ describe('mutations', () => {
data: undefined,
error: null,
failureCount: 1,
failureReason: 'err',
isPaused: true,
status: 'loading',
variables: 'todo',
Expand All @@ -275,6 +284,7 @@ describe('mutations', () => {
data: undefined,
error: null,
failureCount: 1,
failureReason: 'err',
isPaused: true,
status: 'loading',
variables: 'todo',
Expand All @@ -286,7 +296,8 @@ describe('mutations', () => {
context: 'todo',
data: 'todo',
error: null,
failureCount: 1,
failureCount: 0,
failureReason: null,
isPaused: false,
status: 'success',
variables: 'todo',
Expand Down Expand Up @@ -316,6 +327,7 @@ describe('mutations', () => {
data: 'new',
error: undefined,
failureCount: 0,
failureReason: null,
isPaused: false,
status: 'success',
})
Expand Down
1 change: 1 addition & 0 deletions packages/query-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ export interface QueryObserverBaseResult<TData = unknown, TError = unknown> {
error: TError | null
errorUpdatedAt: number
failureCount: number
failureReason: TError | null
errorUpdateCount: number
isError: boolean
isFetched: boolean
Expand Down
2 changes: 2 additions & 0 deletions packages/react-query/src/__tests__/useInfiniteQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ describe('useInfiniteQuery', () => {
error: null,
errorUpdatedAt: 0,
failureCount: 0,
failureReason: null,
errorUpdateCount: 0,
fetchNextPage: expect.any(Function),
fetchPreviousPage: expect.any(Function),
Expand Down Expand Up @@ -104,6 +105,7 @@ describe('useInfiniteQuery', () => {
error: null,
errorUpdatedAt: 0,
failureCount: 0,
failureReason: null,
errorUpdateCount: 0,
fetchNextPage: expect.any(Function),
fetchPreviousPage: expect.any(Function),
Expand Down
Loading

0 comments on commit 07c9631

Please sign in to comment.