new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

TanStack Query · React · all subjects

queries

310 notes in this subject, read out of this brain and free to use. This is page 2 of 6.

QueriesObserver for watching multiple queries

In React Query v3, QueriesObserver can be used to create and watch multiple queries. Example: const observer = new QueriesObserver(queryClient, [{ queryKey: ['post', 1], queryFn: fetchPost }, { queryKey: ['post', 2], queryFn: fetchPost }]); const unsubscribe = observer.subscribe((result) => { console.log(result) })

Query key parts no longer automatically spread to query function

In React Query v3, query key parts are no longer automatically spread to the query function. Use inline functions to pass parameters: useQuery(['post', id], () => fetchPost(id)). Alternatively, use the QueryFunctionContext object: useQuery(['post', id], (context) => fetchPost(context.queryKey[1]))

QueryClient.setQueryDefaults() for default options

In React Query v3, QueryClient.setQueryDefaults() method sets default options for specific queries. Example: queryClient.setQueryDefaults(['posts'], { queryFn: fetchPosts }); then useQuery(['posts']) will use those defaults.

React Query core separated from React

In React Query v3, the core is fully separated from React and can be used standalone or in other frameworks. Use the react-query/core entry point to import only core functionality. Example: import { QueryClient } from 'react-query/core'

useIsFetching() with query filters

In React Query v3, useIsFetching() hook now accepts filters which can be used to show a spinner for certain types of queries. Example: const fetches = useIsFetching({ queryKey: ['posts'] })

useQueries hook for variable-length parallel queries

In React Query v3, the new useQueries() hook enables running multiple queries in parallel without breaking the rules of hooks. Example: const results = useQueries([{ queryKey: ['post', 1], queryFn: fetchPost }, { queryKey: ['post', 2], queryFn: fetchPost }]). Returns an array of results.

Query data selectors with select option

In React Query v3, useQuery and useInfiniteQuery hooks have a select option to select or transform parts of the query result. Example: useQuery(['user'], fetchUser, { select: (user) => user.username }). Set notifyOnChangeProps to ['data', 'error'] to only re-render when the selected data changes.

QueryStatus changed from enum to union type

In React Query v3, QueryStatus has been changed from an enum to a union type. String literals must be used instead of enum properties: QueryStatus.Idle becomes 'idle', QueryStatus.Loading becomes 'loading', QueryStatus.Error becomes 'error', QueryStatus.Success becomes 'success'.

setLogger() replaces setConsole() in v3

In React Query v3, setConsole() has been replaced by setLogger() function. Example: import { setLogger } from 'react-query'; setLogger({ error: (error) => { Sentry.captureException(error) } }) or setLogger(winston.createLogger())

QueryResult.updatedAt split into dataUpdatedAt and errorUpdatedAt

In React Query v3, the QueryResult.updatedAt property has been split into QueryResult.dataUpdatedAt and QueryResult.errorUpdatedAt because data and errors can be present at the same time.

QueryResult.clear() renamed to QueryResult.remove()

In React Query v3, the QueryResult.clear() function has been renamed to QueryResult.remove() to better reflect its actual functionality of removing the query from the cache.

notifyOnChangeProps and notifyOnChangePropsExclusions in v3

In React Query v3, the QueryOptions.notifyOnStatusChange option has been superseded by notifyOnChangeProps and notifyOnChangePropsExclusions options. These allow granular configuration of when a component should re-render. Example: useQuery(['user'], fetchUser, { notifyOnChangeProps: ['data', 'error'] }) to only re-render when data or error changes. Or use notifyOnChangePropsExclusions: ['isStale'] to prevent re-render when isStale changes.

queryFnParamsFilter removed in favor of QueryFunctionContext

In React Query v3, the QueryOptions.queryFnParamsFilter option has been removed. Query functions now receive a QueryFunctionContext object instead of the query key. Parameters can be filtered within the query function itself since QueryFunctionContext contains the query key.

React Native logging automatic in v3

In React Query v3, React Native no longer requires manually overriding the logger to prevent error screens when a query fails. This is done automatically when React Query is used in React Native.

refetchOnMount now only applies to parent component in v3

In React Query v3, when refetchOnMount is set to false, only the component where the option has been set will not refetch on mount. In previous versions, it prevented all query observers from refetching on mount.

refetchOnMount: 'always' replaces forceFetchOnMount

In React Query v3, the QueryOptions.forceFetchOnMount option has been replaced by refetchOnMount: 'always'.

QueryOptions.initialStale removed in v3

In React Query v3, the QueryOptions.initialStale option has been removed. Initial data is now treated as regular data, which means if initialData is provided, the query will refetch on mount by default. To prevent immediate refetch, define a staleTime.

QueryObserver for watching queries

In React Query v3, QueryObserver can be used to create and watch a query outside of React components. Example: const observer = new QueryObserver(queryClient, { queryKey: 'posts' }); const unsubscribe = observer.subscribe((result) => { console.log(result) })

QueryOptions.enabled must be boolean in v3

In React Query v3, if set, the QueryOptions.enabled option must be a boolean (true/false). It will only disable a query when the value is false. Values can be casted with !!userId or Boolean(userId), and an error will be thrown if a non-boolean value is passed.

useQuery object syntax uses collapsed config in v3

In React Query v3, the useQuery object syntax no longer uses a nested config property. Options are flattened directly: useQuery({ queryKey: 'posts', queryFn: fetchPosts, staleTime: Infinity }) instead of useQuery({ queryKey: 'posts', queryFn: fetchPosts, config: { staleTime: Infinity } })

keepPreviousData option replaces usePaginatedQuery

In React Query v3, usePaginatedQuery() has been removed in favor of the keepPreviousData option. This option is available for both useQuery and useInfiniteQuery and provides the same lagging effect on data. Example: useQuery(['page', page], fetchPage, { keepPreviousData: true })

v5 new dedicated suspense hooks

In v5, suspense for data fetching is now stable. New dedicated hooks useSuspenseQuery, useSuspenseInfiniteQuery, and useSuspenseQueries have been added. With these hooks, data will never be potentially undefined on the type level. The experimental suspense: boolean flag on the query hooks has been removed.

v5 typesafe way to create query options

In v5, there is a new typesafe way to create query options. See the TypeScript documentation for details on typing query options.

v5 new combine option for useQueries

In v5, useQueries has a new combine option for combining results. See the useQueries documentation for more details.

isPlaceholderData flag usage

The isPlaceholderData flag indicates whether the data currently returned by the query is placeholder data or real data, allowing you to disable next page buttons until actual data confirms more pages are available.

UI jumping between states in paginated queries

When each new page is treated as a brand new query with a different query key, the UI jumps in and out of success and pending states, creating a poor user experience.

Paginated query example with keepPreviousData

Example showing paginated queries with keepPreviousData: ```tsx import { keepPreviousData, useQuery } from '@tanstack/react-query' import React from 'react' function Todos() { const [page, setPage] = React.useState(0) const fetchProjects = (page = 0) => fetch('/api/projects?page=' + page).then((res) => res.json()) const { isPending, isError, error, data, isFetching, isPlaceholderData } = useQuery({ queryKey: ['projects', page], queryFn: () => fetchProjects(page), placeholderData: keepPreviousData, }) return ( <div> {isPending ? ( <div>Loading...</div> ) : isError ? ( <div>Error: {error.message}</div> ) : ( <div> {data.projects.map((project) => ( <p key={project.id}>{project.name}</p> ))} </div> )} <span>Current Page: {page + 1}</span> <button onClick={() => setPage((old) => Math.max(old - 1, 0))} disabled={page === 0} > Previous Page </button> <button onClick={() => { if (!isPlaceholderData && data.hasMore) { setPage((old) => old + 1) } }} disabled={isPlaceholderData || !data?.hasMore} > Next Page </button> {isFetching ? <span> Loading...</span> : null} </div> ) } ```

Paginated queries with page in queryKey

To render paginated data in TanStack Query, include the page information in the query key. For example, use queryKey: ['projects', page] and queryFn: () => fetchProjects(page).

Benefits of placeholderData in pagination

Using placeholderData provides three benefits: the data from the last successful fetch is available while new data is being requested even though the query key has changed; when new data arrives, the previous data is seamlessly swapped to show the new data; and isPlaceholderData is made available to know what data the query is currently providing.

keepPreviousData function

TanStack Query exports a keepPreviousData function that can be used as the placeholderData option to maintain the data from the last successful fetch while new data is being requested.

placeholderData option for paginated queries

The placeholderData option allows you to provide data while new data is being fetched after the query key changes. You can set placeholderData to (previousData) => previousData or use the keepPreviousData function exported from TanStack Query.

Suspense mode parallel queries pitfall

When using React Query in suspense mode, the pattern of manual parallelism does not work, since the first query would throw a promise internally and would suspend the component before the other queries run. To get around this, you need to use the useSuspenseQueries hook (suggested) or orchestrate your own parallelism with separate components for each useSuspenseQuery instance.

useQueries TypeScript select type inference limitation

When using TypeScript, an inline select written on a query object passed to useQueries cannot infer its data argument from that same object's queryFn — it falls back to unknown. Annotate the select parameter explicitly, or define the query with the queryOptions helper to keep type inference.

useQueries hook API

useQueries accepts an options object with a queries key whose value is an array of query objects. It returns an array of query results.

Dynamic parallel queries with useQueries

If the number of queries you need to execute is changing from render to render, you cannot use manual querying since that would violate the rules of hooks. Instead, use the useQueries hook to dynamically execute as many queries in parallel as needed.

Manual parallel queries example

Example of executing queries in parallel: function App () { const usersQuery = useQuery({ queryKey: ['users'], queryFn: fetchUsers }) const teamsQuery = useQuery({ queryKey: ['teams'], queryFn: fetchTeams }) const projectsQuery = useQuery({ queryKey: ['projects'], queryFn: fetchProjects }) } This shows three useQuery hooks called side-by-side to execute queries in parallel.

Manual parallel queries no extra effort

When the number of parallel queries does not change, there is no extra effort to use parallel queries. Just use any number of TanStack Query's useQuery and useInfiniteQuery hooks side-by-side.

Parallel queries definition

Parallel queries are queries that are executed in parallel, or at the same time so as to maximize fetching concurrency.

useQueries example

Example of using useQueries to dynamically execute parallel queries: function App({ users }) { const userQueries = useQueries({ queries: users.map((user) => { return { queryKey: ['user', user.id], queryFn: () => fetchUserById(user.id), } }), }) } This maps over an array of users and creates a query for each user.

Memoizing placeholder data

If the process for accessing placeholder data is intensive or not something you want to perform on every render, you can memoize the value using useMemo to avoid recalculation.

Declaring placeholder data as a value

Placeholder data can be provided declaratively by passing a placeholderData option to useQuery with a static value or variable.

Placeholder data from cache example

Example of providing placeholder data for a query from the cached result of another query, such as using preview data from a blog post list query as placeholder data for an individual post query.

Placeholder data function example

Example of using placeholderData as a function to access previous query data.

Placeholder data as a function

placeholderData can be a function that receives previousData and previousQuery parameters, allowing you to access data from a previous successful Query. This is useful for using data from one query as placeholder data for another query, such as in paginated queries where you can keep displaying old data instead of showing a loading spinner while data transitions from one query to the next.

Memoized placeholder data example

Example of memoizing placeholder data generation to avoid recalculation on every render.

Query state with placeholder data

When placeholderData is used, the Query will not be in a pending state. It will start out as being in success state because there is data to display, even if that data is placeholder data. The isPlaceholderData flag will be set to true on the Query result to distinguish placeholder data from real data.

Placeholder data definition and behavior

Placeholder data allows a query to behave as if it already has data, similar to initialData, but the data is not persisted to the cache. It is useful for situations where you have partial or fake data to render the query successfully while the actual data is fetched in the background.

refetchInterval makes query refetch on a timer

The refetchInterval option makes a query refetch on a timer. Set it to a number in milliseconds and the query runs every N ms while there is at least one active observer.

Polling example with adaptive refetchInterval function

Example of polling with an adaptive interval that stops when a job completes: ```tsx useQuery({ queryKey: ['job', jobId], queryFn: () => fetchJobStatus(jobId), refetchInterval: (query) => { // Stop polling once the job finishes if (query.state.data?.status === 'complete') return false return 2_000 }, }) ```

Polling example with background refetching

Example of polling that continues even when the browser tab is not focused: ```tsx useQuery({ queryKey: ['portfolio'], queryFn: fetchPortfolio, refetchInterval: 30_000, refetchIntervalInBackground: true, }) ```

Control polling with a function closing over component state

Pass a function to refetchInterval that can close over component state to dynamically control when polling runs. The function can return false to pause polling when conditions are not met.

Polling example with static refetchInterval

Example of polling with a static interval: ```tsx useQuery({ queryKey: ['prices'], queryFn: fetchPrices, refetchInterval: 5_000, // every 5 seconds }) ```

Polling deduplication at query-level but not observer-level

Each QueryObserver (each component using useQuery with refetchInterval) runs its own timer independently. Two components subscribed to the same key with refetchInterval: 5000 will each fire their timer every 5 seconds. What gets deduplicated is concurrent in-flight fetches: if two timers fire at the same time, only one network request goes out. The timers are observer-level; the deduplication is query-level.

refetchIntervalInBackground for continuous polling when tab is not focused

By default, polling pauses when the browser tab loses focus. Set refetchIntervalInBackground: true to keep polling active even when the user is in another tab, which is useful for dashboards or interfaces where data needs to stay current.

refetchInterval as a function to adapt polling interval

Instead of a static number, refetchInterval can accept a function that receives the Query object and returns a number in milliseconds to set the next interval, or returns false to stop polling. Returning false clears the interval timer. If the query result changes so the function would return a positive number again, polling resumes automatically.

Polling is independent of staleTime

Polling via refetchInterval is independent of staleTime. A query can be fresh and still poll on schedule. The refetchInterval fires on its own clock regardless of freshness.

Polling example with state-based pausing

Example of polling controlled by component state: ```tsx useQuery({ queryKey: ['prices', tokenAddress], queryFn: () => fetchPrice(tokenAddress), refetchInterval: () => { if (!tokenAddress || isPaused) return false return 15_000 }, }) ```

useQuery hook minimum requirements

To subscribe to a query in your components or custom hooks, call the useQuery hook with at least: a unique key for the query (queryKey), and a function that returns a promise that resolves the data or throws an error (queryFn).

Query definition and unique key requirement

A query is a declarative dependency on an asynchronous source of data that is tied to a unique key. A query can be used with any Promise based method (including GET and POST methods) to fetch data from a server. The unique key you provide is used internally for refetching, caching, and sharing your queries throughout your application.

Query result states: isPending, isError, isSuccess

The result object from useQuery contains state indicators. A query can only be in one of the following states at any given moment: isPending (or status === 'pending') means the query has no data yet; isError (or status === 'error') means the query encountered an error; isSuccess (or status === 'success') means the query was successful and data is available.

Give your agent this brain