Repository: tannerlinsley/react-query
File: packages/query-core/src/queryClient.ts (TypeScript)

Code before:
      : TQueryFnData,
  >(queryKey: TTaggedQueryKey): TInferredQueryFnData | undefined
  getQueryData(queryKey: QueryKey) {
    const options = this.defaultQueryOptions({ queryKey })
    return this.#queryCache.get(options.queryHash)?.state.data
  }

  ensureQueryData<
    TQueryFnData,
    TError = DefaultError,
    TData = TQueryFnData,
    TQueryKey extends QueryKey = QueryKey,
  >(
    options: EnsureQueryDataOptions<TQueryFnData, TError, TData, TQueryKey>,
  ): Promise<TData> {
    const defaultedOptions = this.defaultQueryOptions(options)
    const query = this.#queryCache.build(this, defaultedOptions)

    if (query.state.data && query.isStaleByTime(defaultedOptions.staleTime)) {
      query.fetch(defaultedOptions)
    }

    return query.state.data !== undefined
      ? Promise.resolve(query.state.data)
      : this.fetchQuery(options)
  }

  getQueriesData<TQueryFnData = unknown>(
    filters: QueryFilters,
  ): Array<[QueryKey, TQueryFnData | undefined]> {
    return this.getQueryCache()
      .findAll(filters)
      .map(({ queryKey, state }) => {
        const data = state.data as TQueryFnData | undefined
        return [queryKey, data]
      })
  }

  setQueryData<
    TQueryFnData = unknown,
    TTaggedQueryKey extends QueryKey = QueryKey,
    TInferredQueryFnData = TTaggedQueryKey extends DataTag<
      unknown,
      infer TaggedValue
    >
      ? TaggedValue
      : TQueryFnData,
  >(
    queryKey: TTaggedQueryKey,
    updater: Updater<
      NoInfer<TInferredQueryFnData> | undefined,

Review comment (performance):
I think we should generally implement this a bit differently, flow-wise:

- first, look up the `cachedData`
- if it's undefined
  - return fetch
- else 
  - check if that data is stale
  - if it is - trigger a background refetch
  - in any case, return it

```
const cachedData = this.getQueryData<TData>(options.queryKey)

if (cachedData === undefined) {
  return this.fetchQuery(options)
}

const defaultedOptions = this.defaultQueryOptions(options)
if (query.isStaleByTime(defaultedOptions.staleTime)) {
  void this.prefetchQuery(defaultedOptions)
}

return cachedData
```

calling `prefetchQuery` instead of `query.fetch` is important because:

- it catches errors that happen during fetching, which is what we want for a background refetch
- it goes through `fetchQuery`, which turns off retries, which is also what we want:

https://github.com/TanStack/query/blob/bdd2b552d3647242e45c85f4c765fd293862d6d5/packages/query-core/src/queryClient.ts#L329-L331

Code after:
      ? TaggedValue
      : TQueryFnData,
  >(queryKey: TTaggedQueryKey): TInferredQueryFnData | undefined
  getQueryData(queryKey: QueryKey) {
    const options = this.defaultQueryOptions({ queryKey })
    return this.#queryCache.get(options.queryHash)?.state.data
  }

  ensureQueryData<
    TQueryFnData,
    TError = DefaultError,
    TData = TQueryFnData,
    TQueryKey extends QueryKey = QueryKey,
  >(
    options: EnsureQueryDataOptions<TQueryFnData, TError, TData, TQueryKey>,
  ): Promise<TData> {
    const cachedData = this.getQueryData<TData>(options.queryKey)

    if (cachedData === undefined) return this.fetchQuery(options)
    else {
      const defaultedOptions = this.defaultQueryOptions(options)
      const query = this.#queryCache.build(this, defaultedOptions)

      if (
        options.revalidateIfStale &&
        query.isStaleByTime(defaultedOptions.staleTime)
      ) {
        void this.prefetchQuery(defaultedOptions)
      }

      return Promise.resolve(cachedData)
    }
  }

  getQueriesData<TQueryFnData = unknown>(
    filters: QueryFilters,
  ): Array<[QueryKey, TQueryFnData | undefined]> {
    return this.getQueryCache()
      .findAll(filters)
      .map(({ queryKey, state }) => {
        const data = state.data as TQueryFnData | undefined
        return [queryKey, data]
      })
  }

  setQueryData<
    TQueryFnData = unknown,
    TTaggedQueryKey extends QueryKey = QueryKey,
    TInferredQueryFnData = TTaggedQueryKey extends DataTag<
      unknown,
      infer TaggedValue