This article explains how to migrate your application to React Query 3.
The QueryCache
has been split into a QueryClient
and a QueryCache
.
The QueryCache
contains all cached queries and the QueryClient
can be used to interact with a cache.
This has some benefits:
Use the QueryClientProvider
component to connect a QueryClient
to your application:
import { QueryClient, QueryClientProvider, QueryCache } from 'react-query'const cache = new QueryCache()const client = new QueryClient({ cache })function App() {return <QueryClientProvider client={client}>...</QueryClientProvider>}
The useQueryCache()
hook has been replaced by the useQueryClient()
hook:
import { useCallback } from 'react'import { useQueryClient } from 'react-query'function Todo() {const client = useQueryClient()const onClickButton = useCallback(() => {client.invalidateQueries('posts')}, [client])return <button onClick={onClickButton}>Refetch</button>}
The ReactQueryConfigProvider
component has been removed. Default options for queries and mutations can now be specified in QueryClient
:
const client = new QueryClient({cache,defaultOptions: {queries: {staleTime: Infinity,},},})
The usePaginatedQuery()
hook has been replaced by the keepPreviousData
option on useQuery
:
import { useQuery } from 'react-query'function Page({ page }) {const { data } = useQuery(['page', page], fetchPage, {keepPreviousData: true,})}
The object syntax has been collapsed:
// Old:useQuery({queryKey: 'posts',queryFn: fetchPosts,config: { staleTime: Infinity },})// New:useQuery({queryKey: 'posts',queryFn: fetchPosts,staleTime: Infinity,})
The client.prefetchQuery()
method should now only be used for prefetching scenarios where the result is not relevant.
Use the client.fetchQueryData()
method to get the query data or error:
// Prefetch a query:await client.prefetchQuery('posts', fetchPosts)// Fetch a query:try {const data = await client.fetchQueryData('posts', fetchPosts)} catch (error) {// Error handling}
The ReactQueryCacheProvider
component has been replaced by the QueryClientProvider
component.
The makeQueryCache()
function has replaced by new QueryCache()
.
The ReactQueryErrorResetBoundary
component has been renamed to QueryErrorResetBoundary
.
The queryCache.resetErrorBoundaries()
method has been replaced by the QueryErrorResetBoundary
component.
The queryCache.getQuery()
method has been replaced by cache.find()
.
The queryCache.getQueries()
method has been replaced by cache.findAll()
.
The queryCache.isFetching
property has been replaced by client.isFetching()
.
The enabled
query option will now only disable a query when the value is false
.
If needed, values can be casted with !!userId
or Boolean(userId)
.
The initialStale
query option has been removed and initial data is now treated as regular data.
Which means that if initialData
is provided, the query will refetch on mount by default.
If you do not want to refetch immediately, you can define a staleTime
.
The forceFetchOnMount
query option has been replaced by refetchOnMount: 'always'
.
When refetchOnMount
was set to false
any additional components were prevented from refetching on mount.
In version 3 only the component where the option has been set will not refetch on mount.
The QueryResult.clear()
method has been renamed to QueryResult.remove()
.
The setConsole
function has been replaced by setLogger
:
import { setLogger } from 'react-query'// Log with SentrysetLogger({error: error => {Sentry.captureException(error)},})// Log with WinstonsetLogger(winston.createLogger())
To prevent showing error screens in React Native when a query fails it was necessary to manually change the Console:
import { setConsole } from 'react-query'setConsole({log: console.log,warn: console.warn,error: console.warn,})
In version 3 this is done automatically when React Query is used in React Native.
Some new features have also been added besides the API changes, performance improvements and file size reduction.
The useQuery
and useInfiniteQuery
hooks now have a select
option to select or transform parts of the query result.
import { useQuery } from 'react-query'function User() {const { data } = useQuery('user', fetchUser, {select: user => user.username,})return <div>Username: {data}</div>}
Set the notifyOnStatusChange
option to false
to only re-render when the selected data changes.
The useQueries()
hook can be used to fetch a variable number of queries:
import { useQueries } from 'react-query'function Overview() {const results = useQueries([{ queryKey: ['post', 1], queryFn: fetchPost },{ queryKey: ['post', 2], queryFn: fetchPost },])return (<ul>{results.map(({ data }) => data && <li key={data.id}>{data.title})</li>)}</ul>)}
The client.watchQuery()
method can be used to create and/or watch a query:
const observer = client.watchQuery('posts')const unsubscribe = observer.subscribe(result => {console.log(result)unsubscribe()})
The client.watchQueries()
method can be used to create and/or watch multiple queries:
const observer = client.watchQueries([{ queryKey: ['post', 1], queryFn: fetchPost },{ queryKey: ['post', 2], queryFn: fetchPost },])const unsubscribe = observer.subscribe(result => {console.log(result)unsubscribe()})
client.setQueryDefaults
The client.setQueryDefaults()
method to set default options for a specific query. If the query does not exist yet it will create it.
client.setQueryDefaults('posts', fetchPosts)function Component() {const { data } = useQuery('posts')}
The useIsFetching()
hook now accepts filters which can be used to for example only show a spinner for certain type of queries:
const fetches = useIsFetching(['posts'])
The core of React Query is now fully separated from React, which means it can also be used standalone or in other frameworks. Use the react-query/core
entrypoint to only import the core functionality:
import { QueryClient } from 'react-query/core'
The latest TanStack news, articles, and resources, sent to your inbox.