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 5 of 6.

Browser compatibility for React Query

React Query is compatible with Chrome >= 91, Firefox >= 90, Edge >= 91, Safari >= 15, iOS >= 15, and Opera >= 77.

Install TanStack React Query via pnpm

Install the @tanstack/react-query package using pnpm with the command: pnpm add @tanstack/react-query

Install TanStack React Query via yarn

Install the @tanstack/react-query package using yarn with the command: yarn add @tanstack/react-query

Install TanStack React Query via bun

Install the @tanstack/react-query package using bun with the command: bun add @tanstack/react-query

Install TanStack React Query via deno

Install the @tanstack/react-query package using deno with the command: deno add @tanstack/react-query

React Query compatibility with React versions

React Query is compatible with React v18 and above, and works with ReactDOM and React Native.

Use TanStack React Query via CDN with ESM.sh

You can use TanStack React Query via an ESM-compatible CDN such as ESM.sh by adding a <script type="module"> tag to your HTML file. Example: import { QueryClient } from 'https://esm.sh/@tanstack/react-query'

Install ESLint Plugin Query

It is recommended to install the @tanstack/eslint-plugin-query ESLint plugin to help catch bugs and inconsistencies while coding. Install via npm: npm i -D @tanstack/eslint-plugin-query, pnpm: pnpm add -D @tanstack/eslint-plugin-query, yarn: yarn add -D @tanstack/eslint-plugin-query, or bun: bun add -D @tanstack/eslint-plugin-query

Polyfills may be needed for older browsers

Depending on your environment, you might need to add polyfills. If you want to support older browsers, you need to transpile the library from node_modules yourself.

AsyncStorage persister retry behavior

Retries for asyncStoragePersister work similarly to SyncStoragePersister but can be asynchronous. All predefined retry handlers are supported.

createAsyncStoragePersister options reference

CreateAsyncStoragePersisterOptions interface accepts: storage (AsyncStorage | undefined | null, required), key (string, optional), throttleTime (number in ms to throttle cache saving, optional), serialize (function to serialize PersistedClient to string, optional), deserialize (function to deserialize string to PersistedClient, optional), and retry (AsyncPersistRetryer for error handling, optional).

createAsyncStoragePersister basic setup

Import createAsyncStoragePersister, create an asyncStoragePersister by passing a storage object that adheres to the AsyncStorage interface, then wrap your app with PersistQueryClientProvider and pass the persister in persistOptions.

createAsyncStoragePersister default options

Default options are: key = 'REACT_QUERY_OFFLINE_CACHE', throttleTime = 1000 (ms), serialize = JSON.stringify, deserialize = JSON.parse.

createAsyncStoragePersister example with React Native

This example shows creating a QueryClient with 24-hour gcTime, creating an asyncStoragePersister from React Native AsyncStorage, and wrapping the app with PersistQueryClientProvider: ```tsx import AsyncStorage from '@react-native-async-storage/async-storage' import { QueryClient } from '@tanstack/react-query' import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client' import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister' const queryClient = new QueryClient({ defaultOptions: { queries: { gcTime: 1000 * 60 * 60 * 24, // 24 hours }, }, }) const asyncStoragePersister = createAsyncStoragePersister({ storage: AsyncStorage, }) const Root = () => ( <PersistQueryClientProvider client={queryClient} persistOptions={{ persister: asyncStoragePersister }} > <App /> </PersistQueryClientProvider> ) export default Root ```

AsyncStorage interface definition

The AsyncStorage interface requires: getItem(key: string) returning MaybePromise<TStorageValue | undefined | null>; setItem(key: string, value: TStorageValue) returning MaybePromise<unknown>; removeItem(key: string) returning MaybePromise<void>; and an optional entries() method returning MaybePromise<Array<[key: string, value: TStorageValue]>>. Both synchronous storages like window.localStorage and asynchronous storages like React Native AsyncStorage comply with this interface.

experimental_createQueryPersister StoragePersisterOptions interface

StoragePersisterOptions has the following fields: storage (AsyncStorage | Storage | undefined | null, required, the storage client for setting and retrieving cache items), serialize (optional, default JSON.stringify, function to serialize persisted query to storage), deserialize (optional, default JSON.parse, function to deserialize persisted query from storage), buster (optional string for forcefully invalidating existing caches that do not share the same buster), maxAge (optional number in milliseconds, default 24 hours, max-allowed age of cache), prefix (optional string for storage key, prefixed to query hash as 'prefix-queryHash', default 'tanstack-query'), refetchOnRestore (optional boolean or 'always', default true, whether to refetch on successful restoration if data is stale), filters (optional QueryFilters to narrow down which queries should be persisted).

experimental_createQueryPersister and optimistic updates limitation

queryClient.setQueryData() operations are not persisted. If an optimistic update is performed and the page is refreshed before the query is invalidated, the changes to query data will be lost. The persistQueryByKey utility can be used to persist optimistic updates to storage without waiting for invalidation.

experimental_createQueryPersister lazy restoration and staleTime

Queries are lazily restored when first used and do not need throttling. staleTime is respected after restoring a query. If data is stale, it will be refetched immediately after restoration. If data is fresh, the queryFn will not run.

experimental_createQueryPersister memory efficiency with garbage collection

Garbage collecting a query from memory does not affect persisted data. Queries can be kept in memory for shorter periods to be more memory efficient and will be restored from persistent storage when used again.

experimental_createQueryPersister wraps queryFn and defaults networkMode

The createPersister plugin wraps the queryFn and acts as a caching layer between the query and the network. The networkMode defaults to 'offlineFirst' when a persister is used, allowing restoration from persistent storage even without a network connection.

persistQueryByKey utility function

The persister returns a persistQueryByKey(queryKey: QueryKey, queryClient: QueryClient): Promise<void> function that persists a query to storage by key. It can be used with setQueryData to persist optimistic updates to storage without waiting for invalidation.

retrieveQuery utility function

The persister returns a retrieveQuery<T>(queryHash: string): Promise<T | undefined> function that attempts to retrieve a persisted query by queryHash. If the query is expired, busted, or malformed, it is removed from storage and undefined is returned.

persisterGc utility function

The persister returns a persisterGc(): Promise<void> function that can be used to sporadically clean up storage from expired, busted, or malformed entries. The storage must expose an entries method that returns a key-value tuple array, such as Object.entries(localStorage) or entries from idb-keyval.

restoreQueries utility function

The persister returns a restoreQueries(queryClient: QueryClient, filters): Promise<void> function that restores queries currently stored by the persister. It supports filter properties: queryKey to match on a specific key, and exact: boolean to search queries inclusively or only for exact query key matches. The storage must expose an entries method.

removeQueries utility function

The persister returns a removeQueries(filters): Promise<void> function to remove queries currently stored by the persister. When using queryClient.removeQueries, the data remains in the persister and must be removed separately with this function. It supports filter properties: queryKey to match on a specific key, and exact: boolean for inclusive or exact matching. The storage must expose an entries method.

experimental_createQueryPersister per-query vs client-wide persistence

If the persister is passed as defaultOptions, all queries will be persisted to storage, optionally narrowed with filters. Unlike the persistClient plugin, this does not persist the whole query client as a single item but persists each query separately. If provided to a single useQuery hook, only that query will be persisted.

AsyncStorage interface

AsyncStorage interface has the following required methods: getItem(key: string): MaybePromise<TStorageValue | undefined | null>, setItem(key: string, value: TStorageValue): MaybePromise<unknown>, removeItem(key: string): MaybePromise<void>. It has one optional method: entries(): MaybePromise<Array<[key: string, value: TStorageValue]>>. The generic type TStorageValue defaults to string.

experimental_createQueryPersister example with React Native AsyncStorage

Example code showing basic setup: import AsyncStorage from '@react-native-async-storage/async-storage'; import { QueryClient } from '@tanstack/react-query'; import { experimental_createQueryPersister } from '@tanstack/query-persist-client-core'; const persister = experimental_createQueryPersister({ storage: AsyncStorage, maxAge: 1000 * 60 * 60 * 12, }); const queryClient = new QueryClient({ defaultOptions: { queries: { gcTime: 1000 * 30, persister: persister.persisterFn, }, }, });

persistQueryByKey example with optimistic updates

Example showing persistQueryByKey usage with optimistic updates: const persister = experimental_createQueryPersister({ storage: AsyncStorage, maxAge: 1000 * 60 * 60 * 12, }); const queryClient = useQueryClient(); useMutation({ mutationFn: updateTodo, onMutate: async (newTodo) => { queryClient.setQueryData(['todos'], (old) => [...old, newTodo]); persister.persistQueryByKey(['todos'], queryClient); }, });

experimental_createQueryPersister installation

The experimental_createQueryPersister utility comes as a separate package available under the '@tanstack/query-persist-client-core' import. It can be installed via npm, pnpm, yarn, or bun. It is also included in the '@tanstack/react-query-persist-client' package, so it does not need to be installed separately if using that package.

experimental_createQueryPersister basic usage

Import the experimental_createQueryPersister function and pass any storage that adheres to the AsyncStorage interface. Pass the persister as an option to a Query via either the QueryClient defaultOptions or to a specific useQuery hook instance. Each query is lazily restored when first used and persisted after each queryFn run. The query hash is used as the storage key.

Three core concepts of TanStack Query

The three core concepts of TanStack Query are Queries, Mutations, and Query Invalidation. These concepts make up most of the core functionality of the library.

QueryClientProvider setup pattern

To use TanStack Query, create a QueryClient instance with new QueryClient(), then wrap your app with QueryClientProvider and pass the client as the client prop.

useQuery hook basic usage

The useQuery hook accepts an object with queryKey and queryFn properties. The queryKey is an array used to identify the query (e.g., ['todos']), and queryFn is the async function that fetches the data. The hook returns an object containing data and other properties.

useQueryClient hook for accessing client in components

Use the useQueryClient hook within components wrapped by QueryClientProvider to access the QueryClient instance and call methods like invalidateQueries.

Quick start example with useQuery, useMutation, and invalidation

This example demonstrates a complete workflow: creating a QueryClient, providing it via QueryClientProvider, using useQuery to fetch todos, using useMutation to post a todo, and calling queryClient.invalidateQueries() in the onSuccess callback to refetch after mutation.

Refetch on app focus example code

Example code for refetching on app focus: import { useEffect } from 'react'; import { AppState, Platform } from 'react-native'; import type { AppStateStatus } from 'react-native'; import { focusManager } from '@tanstack/react-query'; function onAppStateChange(status: AppStateStatus) { if (Platform.OS !== 'web') { focusManager.setFocused(status === 'active') } } useEffect(() => { const subscription = AppState.addEventListener('change', onAppStateChange); return () => subscription.remove() }, [])

useRefreshOnFocus hook for React Navigation

Example code for a custom hook that refetches stale queries on screen focus: import React from 'react'; import { useFocusEffect } from '@react-navigation/native'; import { useQueryClient } from '@tanstack/react-query'; export function useRefreshOnFocus() { const queryClient = useQueryClient(); const firstTimeRef = React.useRef(true); useFocusEffect(React.useCallback(() => { if (firstTimeRef.current) { firstTimeRef.current = false; return; } queryClient.refetchQueries({ queryKey: ['posts'], stale: true, type: 'active' }) }, [queryClient])) }

Disable queries when screen is out of focus using subscribed prop

Use the subscribed prop on useQuery to control whether a query stays subscribed to updates. When subscribed is false, the query unsubscribes from updates and won't trigger re-renders or fetch new data. Combine with React Navigation's useIsFocused to unsubscribe from queries when a screen isn't focused.

subscribed prop usage example

Example code showing how to use the subscribed prop: import React from 'react'; import { useIsFocused } from '@react-navigation/native'; import { useQuery } from '@tanstack/react-query'; import { Text } from 'react-native'; function MyComponent() { const isFocused = useIsFocused(); const { dataUpdatedAt } = useQuery({ queryKey: ['key'], queryFn: () => fetch(...), subscribed: isFocused }); return <Text>DataUpdatedAt: {dataUpdatedAt}</Text> }

React Query works out of the box with React Native

React Query is designed to work out of the box with React Native.

Refetch on app focus using focusManager

In React Native, use the AppState module to detect app focus changes instead of window event listeners. Use focusManager.setFocused(status === 'active') in an AppState 'change' event listener to trigger refetch when the app state becomes 'active'. Only do this for non-web platforms using Platform.OS !== 'web'.

Refetch stale queries on React Navigation screen focus

Create a custom hook using useFocusEffect from React Navigation to refetch all active stale queries when a screen regains focus. Skip the initial focus (when screen first mounts) to avoid unnecessary refetches.

QueryClientProvider example

This example demonstrates the basic setup of QueryClientProvider: ```tsx import { QueryClient, QueryClientProvider } from '@tanstack/react-query' const queryClient = new QueryClient() function App() { return <QueryClientProvider client={queryClient}>...</QueryClientProvider> } ```

QueryClientProvider component setup

The QueryClientProvider component connects and provides a QueryClient to your application. Import QueryClient and QueryClientProvider from '@tanstack/react-query', create a QueryClient instance, and wrap your application with QueryClientProvider passing the client as a prop.

QueryClientProvider required prop

QueryClientProvider requires a 'client' prop that accepts a QueryClient instance.

queryOptions queryKey parameter

queryKey is a required parameter of type QueryKey passed to queryOptions. It specifies the query key to generate options for.

queryOptions experimental_prefetchInRender option

experimental_prefetchInRender is an optional boolean parameter (defaults to false). When set to true, queries will be prefetched during render, which can be useful for certain optimization scenarios. This option needs to be enabled for the experimental useQuery().promise functionality.

queryOptions excess properties with prefetchQuery

Some options passed to queryOptions will have no effect when forwarded to functions like queryClient.prefetchQuery, but TypeScript will still accept these excess properties without type errors.

queryOptions function signature and purpose

queryOptions is a function that takes a queryKey and options object to generate query options. It accepts everything that can be passed to useQuery.

useIsFetching options and return type

useIsFetching accepts an options object with two properties: filters (of type QueryFilters, used to filter which queries to count) and queryClient (optional, to use a custom QueryClient instead of the one from the nearest context). The hook returns isFetching as a number representing the count of queries currently loading or fetching in the background.

useIsFetching import

Import useIsFetching from '@tanstack/react-query'.

useIsFetching hook basic usage

useIsFetching is an optional hook that returns the number of queries that the application is loading or fetching in the background. It is useful for app-wide loading indicators. Call useIsFetching() with no arguments to get the total count of all queries that are currently fetching.

useIsFetching with query key filtering

useIsFetching can be called with a queryKey option to filter the count to only queries matching that key prefix. For example, useIsFetching({ queryKey: ['posts'] }) returns only the count of queries with the 'posts' prefix that are currently fetching.

useQueries return value ordering

The useQueries hook returns an array with all query results. The order of results returned is the same as the order of queries in the input array.

useQueries combine function example

Example of using combine to transform query results: const combinedQueries = useQueries({ queries: ids.map((id) => ({ queryKey: ['post', id], queryFn: () => fetchPost(id), })), combine: (results) => { return { data: results.map((result) => result.data), pending: results.some((result) => result.isPending), } }, })

useQueries combine function memoization behavior

The combine function only re-runs when the combine function itself changes referentially or when any query results change. An inlined combine function will run on every render. To optimize, wrap the combine function with useCallback or extract it to a stable function reference without dependencies.

useQueries duplicate query keys data sharing pitfall

Having the same query key more than once in the array of query objects may cause data to be shared between queries. To avoid this, consider de-duplicating the queries and mapping the results back to the desired structure.

useQueries placeholderData behavior

The placeholderData option exists for useQueries but does not receive information from previously rendered queries like useQuery does, because useQueries can have a different number of queries on each render.

useQueries hook basic usage

The useQueries hook can be used to fetch a variable number of queries. It accepts an options object with a queries key containing an array of query option objects identical to useQuery options (excluding queryClient). Example: const ids = [1, 2, 3]; const results = useQueries({ queries: ids.map((id) => ({ queryKey: ['post', id], queryFn: () => fetchPost(id), staleTime: Infinity, })), })

Give your agent this brain