* Fetches the query, i.e. runs its `queryFn` (through any configured * retryer/behavior) and updates the query's state with the result. * - If a fetch is already in flight, returns its promise instead of * starting a new one, unless `fetchOptions.cancelRefetch` is set and the * query
(
options?: QueryOptions<TQueryFnData, TError, TData, TQueryKey>,
fetchOptions?: FetchOptions<TQueryFnData>,
)
| 588 | * before fetching. |
| 589 | */ |
| 590 | async fetch( |
| 591 | options?: QueryOptions<TQueryFnData, TError, TData, TQueryKey>, |
| 592 | fetchOptions?: FetchOptions<TQueryFnData>, |
| 593 | ): Promise<TData> { |
| 594 | if ( |
| 595 | this.state.fetchStatus !== 'idle' && |
| 596 | // If the promise in the retryer is already rejected, we have to definitely |
| 597 | // re-start the fetch; there is a chance that the query is still in a |
| 598 | // pending state when that happens |
| 599 | this.#retryer?.status() !== 'rejected' |
| 600 | ) { |
| 601 | if (this.state.data !== undefined && fetchOptions?.cancelRefetch) { |
| 602 | // Silently cancel current fetch if the user wants to cancel refetch |
| 603 | this.cancel({ silent: true }) |
| 604 | } else if (this.#retryer) { |
| 605 | // make sure that retries that were potentially cancelled due to unmounts can continue |
| 606 | this.#retryer.continueRetry() |
| 607 | // Return current promise if we are already fetching |
| 608 | return this.#retryer.promise |
| 609 | } |
| 610 | } |
| 611 | |
| 612 | // Update config if passed, otherwise the config from the last execution is used |
| 613 | if (options) { |
| 614 | this.setOptions(options) |
| 615 | } |
| 616 | |
| 617 | // Use the options from the first observer with a query function if no function is found. |
| 618 | // This can happen when the query is hydrated or created with setQueryData. |
| 619 | if (!this.options.queryFn) { |
| 620 | const observer = this.observers.find((x) => x.options.queryFn) |
| 621 | if (observer) { |
| 622 | this.setOptions(observer.options) |
| 623 | } |
| 624 | } |
| 625 | |
| 626 | if (process.env.NODE_ENV !== 'production') { |
| 627 | if (!Array.isArray(this.options.queryKey)) { |
| 628 | console.error( |
| 629 | `As of v4, queryKey needs to be an Array. If you are using a string like 'repoData', please change it to an Array, e.g. ['repoData']`, |
| 630 | ) |
| 631 | } |
| 632 | } |
| 633 | |
| 634 | const abortController = new AbortController() |
| 635 | |
| 636 | // Adds an enumerable signal property to the object that |
| 637 | // which sets abortSignalConsumed to true when the signal |
| 638 | // is read. |
| 639 | const addSignalProperty = (object: unknown) => { |
| 640 | Object.defineProperty(object, 'signal', { |
| 641 | enumerable: true, |
| 642 | get: () => { |
| 643 | this.#abortSignalConsumed = true |
| 644 | return abortController.signal |
| 645 | }, |
| 646 | }) |
| 647 | } |
no test coverage detected