Skip to content

Releases: TanStack/query

v2.2.2

25 Jun 01:38
Compare
Choose a tag to compare

2.2.2 (2020-06-25)

Bug Fixes

  • prefetchQuery: add prefetchQuery(key, options) overload (0054f7f)

v2.2.1

24 Jun 23:20
Compare
Choose a tag to compare

2.2.1 (2020-06-24)

Bug Fixes

  • queryKeySerializer now in the right spot of the config (a68dc28)

v2.2.0

24 Jun 22:51
Compare
Choose a tag to compare

2.2.0 (2020-06-24)

Bug Fixes

  • call onSuccess for all query instances (c9afbc9)
  • call onSuccess for all query instances on (a05cb50), closes #629
  • don't schedule garbage collection unnecessarily (#627) (1e1e0f6)

Features

  • add default quernFn option (2a31f8d)

v2.1.1

24 Jun 18:01
Compare
Choose a tag to compare

2.1.1 (2020-06-24)

Bug Fixes

  • query.state.isFetching defaults to the loading status, despite lack of data (fd280ec), closes #624

v2.1.0

24 Jun 17:48
Compare
Choose a tag to compare

2.1.0 (2020-06-24)

Bug Fixes

  • suspense boundaries now catch query errors accurately

Features

  • added queryCache.resetErrorBoundaries (4c741f7)

Whether you are using suspense or useErrorBoundaries in your queries, you will need to know how to use the queryCache.resetErrorBoundaries function to let queries know that you want them to try again when you render them again.

How you trigger this function is up to you, but the most common use case is to do it in something like react-error-boundary's onReset callback:

import { queryCache } from "react-query";
import { ErrorBoundary } from "react-error-boundary";

<ErrorBoundary
  onReset={() => queryCache.resetErrorBoundaries()}
  fallbackRender={({ error, resetErrorBoundary }) => (
    <div>
      There was an error!
      <Button onClick={() => resetErrorBoundary()}>Try again</Button>
    </div>
  )}
>

v2.0.4

24 Jun 16:42
Compare
Choose a tag to compare

2.0.4 (2020-06-24)

Bug Fixes

  • refetchOnWindowFocus: stale queries are no longer refetched (c3e42c4)

v2.0.3

23 Jun 02:04
ebbf1a8
Compare
Choose a tag to compare

2.0.3 (2020-06-23)

Bug Fixes

  • remove unused wasPrefetched (ebbf1a8)

v2.0.2

22 Jun 23:46
Compare
Choose a tag to compare

2.0.2 (2020-06-22)

Bug Fixes

  • retries: cancel retry timer when query is cleared (9c618f3)

v2.0.1

22 Jun 22:03
Compare
Choose a tag to compare

2.0.1 (2020-06-22)

Bug Fixes

  • types: temporarily disable types for 2.0 (8eec19a)

v2.0.0

22 Jun 22:05
Compare
Choose a tag to compare

Summary

  • Better query invalidation & refetching, less over-fetching
  • Simplified dependent query syntax and new idle query state
  • Multi-instance polling and interval support
  • New query status booleans
  • Bidirectional Infinite Queries
  • Improved mutation lifecycle
  • Better test cleanup utils
  • Prep for future SSR enhancements

TYPESCRIPT USERS! Types are currently being updated to use the new 2.0 api and will be available very soon. You can make that happen faster by contributing to them in /types/index.d.ts and testing them in /types/test.ts and opening a PR!

Breaking Changes & Migration Guide

  • Do you use falsy query keys for dependent queries?

    • The new way to do dependent queries to instead use the enabled config flag. You should move your conditions in your key to the enabled option
      • Before
      useQuery(ready && queryKey, queryFn)
      • After
      useQuery(queryKey, queryFn, { enabled: ready })
  • Do you use functions as queryKeys for dependent queries?

    • If you use functions as query keys that can potentially throw, you should migrate their logic to the enabled config option and use optional chaining to cast them to a boolean
      • Before
      useQuery(() => ['user', user.id], queryFn)
      • After
      useQuery(['user', user?.id], queryFn, { enabled: user?.id })
  • Do you expect dependent queries to start in the success state?

    • Dependent queries now start in a new idle state. You should account for this new state where possible. Most rendering logic should still work if you are checking first for the loading and error states first, then falling back to the "success" state, but still... it's a good idea to do this

      • Before
      const { status, data } = useQuery(key, fn)
      
      return status === 'loading'
        ? 'Loading...'
        : status === 'error'
        ? error.message
        : data
        ? 'The Data'
        : 'Not Ready'
      • After
      const { status } = useQuery(key, fn
      
      return status === 'idle' ? 'Not Ready' : status === 'loading'
        ? 'Loading...'
        : status === 'error'
        ? error.message
        : 'The Data'
  • Do you use queryCache.refetchQueries?

    • refetchQueries has been renamed to invalidateQueries. You will need make this rename change for your app to continue working propertly. The name change comes due to some differences in what the function does.
      • Before, any queries that matched the queryKey used in refetchQueries(queryKey) and were also stale, would be refetched... **even queries that were inactive and not rendered on the screen. This resulted in quite a few queries being refetched regardless of their immediate necessity.
      • Now, with invalidateQueries, only queries that are actively rendered will be refetched, while any other matching queries will forcefully be marked as stale.
      • This probably won't affect much performance, but should help reduce overfetching out of the box.
  • Did you expect queryCache.refetchQueries to only refetch stale queries?

    • The new invalidateQueries method will always refetch matching queries that are active. All other matched queries that are not active will be immediately marked as stale.
  • Do you call queryCache.refetchQueries with the force option?

    • Before, the force option was a way to force queries that were not stale to refetch.
    • Now, he new invalidateQueries method will always refetch matching queries that are active and all other matched queries that are not active will be immediately marked as stale.
  • Do you use a global configuration object to configure React Query?

    • Before, the global configuration object was flat:
      const globalConfig = {
        suspense,
        useErrorBoundary,
        throwOnError,
        refetchAllOnWindowFocus,
        queryKeySerializerFn,
        onMutate,
        onSuccess,
        onError,
        onSettled,
        retry,
        retryDelay,
        staleTime,
        cacheTime,
        refetchInterval,
        queryFnParamsFilter,
        refetchOnMount,
        isDataEqual,
      }
    • Now, the global configuration object has 3 parts. The shared section, which is only for the suspense and queryKeySerializerFn options (that are inherited into all others) and the queries and mutations sections, each corresponding to the functionality they are used for in React Query:
      const globalConfig = {
        shared: {
          suspense,
        },
        queries: {
          suspense, // defaults to `shared.suspense`
          queryKeySerializerFn,
          enabled,
          retry,
          retryDelay,
          staleTime,
          cacheTime,
          refetchOnWindowFocus,
          refetchInterval,
          queryFnParamsFilter,
          refetchOnMount,
          isDataEqual,
          onError,
          onSuccess,
          onSettled,
          throwOnError,
          useErrorBoundary,
        },
        mutations: {
          suspense, // defaults to `shared.suspense`
          throwOnError,
          onMutate,
          onError,
          onSuccess,
          onSettled,
          useErrorBoundary,
        },
      }
  • Do you use "optional query variables" eg. useQuery(queryKey, optionalVariables, queryFn) or useQuery({ variables })?

    • Optional variables have been removed. They were not used by many and also were unnecessary seeing how you can inline them into your query function
    • Before
      useQuery('todos', [optional, variables], queryFn)
    • After
      useQuery('todos', (key) => queryFn(key, optional, variables))
  • Do you use the globalConfig.refetchAllOnWindowFocus config option?

    • refetchAllOnWindowFocus has been renamed to refetchOnWindowFocus to match the option in the configuration object for useQuery and friends.
  • Do you use the refetch function returned by useQuery and friends?

    • Previously this refetch function would not trigger an actual refetch if the query is not stale.
    • Now, calling this refetch will always trigger a refetch, regardless if the query is stale or not.
  • Do you expect prefetchQuery to skip the first render of useQuery instances that render after it?

    • Previously, the first useQuery call after a prefetchQuery would be skipped all the time.
    • Now, the staleTime of a prefetchQuery instance is honored. So, if you call prefetchQuery(key, fn, { staletime: 5000 }), and then useQuery(key, fn) is rendered within those initial 5000 milliseconds, the query will not refetch in the background, since it is not stale yet. Likewise, if the stale time has been reached by the time useQuery(key, fn) renders, it will refetch in the background, since it is stale when useQuery mounts/renders.
  • Do you use prefetchQuery's throwOnError or force options?

    • prefetchQuery's throwOnError and force options are now located in a fourth argument, after the query config.
    • Before
      prefetchQuery(key, fn, { ...queryConfig, throwOnError: true, force: true })
    • After
      prefetchQuery(key, fn, queryConfig, { throwOnError: true, force: true })
  • Do you call mutate() with additional side-effect callbacks? eg. mutate(vars, { onError, onSuccess, onSettled })

    • There are no code changes here, however previously, mutate()-level side effects would run before side-effects defined in useMutation. That order has been reversed to make more sense.

    • Now, the side-effect callbacks in useMutation will be fired before their mutate-level counterparts.

    • Before

      const mutate = useMutation(fn, {
        onSuccess: () => console.log('I will run second'),
      })
      
      mutate(vars, { onSuccess: () => console.log('I will run first') })
    • After

      const mutate = useMutation(fn, {
        onSuccess: () => console.log('I will run first'),
      })
      
      mutate(vars, { onSuccess: () => console.log('I will run second') })
  • Do you use setQueryData to update multiple queries with a single query key? eg. setQueryData('todos', newData) and expect queryKeys ['todos', 1] and ['todos', 2] to both get updated?

    • setQueryData no longer allows updating multiple queries at once (via prefix matching). If you need to update multiple queries with the same data, you can use the queryCache.getQueries() function to match all of the queries you want, then loop over them and use their query.setData function to set all of them to the same value.

New Features

  • The booleans isSuccess, isError isLoading and a new one called isIdle have been added to the queryInfo object returned by useQuery (and friends) and useMutation. These are derived safely from the queryInfo.status and are guaranteed to not overlap. In most situations, they are easier to use, less typo-prone than status strings and also more terse for determining what to render based on the status of a query.

    const queryInfo = useQuery(queryKey, fn)
    
    return queryInfo.isLoading ? (
      'Loading...'
    ) : queryInfo.isError ? (
      queryInfo.error.message
    ) : (
      <div>{queryInfo.data}</div>
    )
  • queryCaches is now exported, which allows you to clean up all query caches that were created. We do this in our own tests when multiple caches are used for testing and to be thorough.

    // test.js
    import { queryCaches } from 'react-query'
    
    afterEach(() => {
      queryCaches.forEach((queryCache) => queryCache.clear())
    })
  • fetchMore now supports an optional previous option, which will determine if the data you are fetching is should be prepended instead of appended to your infinite list. eg, fetchMore(nextPageVars, { previous: true })
    ...

Read more