Pmndrs.docs

Query

This doc describes jotai/query bundle.

This is the Jotai integration with react-query, a set of hooks and tools for managing async state (typically external data).

From the React Query docs:

React Query is often described as the missing data-fetching library for React, but in more technical terms, it makes fetching, caching, synchronizing and updating server state in your React applications a breeze.

Jotai with react-query provides a wonderful interface with all of the react-query features, providing you the ability to use those features in combination with your existing Jotai state.

Install

In addition to jotai, you have to install react-query to make use of this bundle and its functions.

yarn add react-query

atomWithQuery

atomWithQuery creates a new atom that implements a standard Query from react-query. This function combines both Jotai atom features and useQuery features in a single atom. This atom supports all features you'd expect to find when using the standard react-query package.

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.

import { useAtom } from 'jotai'
import { atomWithQuery } from 'jotai/query'

const idAtom = atom(1)
const userAtom = atomWithQuery((get) => ({
  queryKey: ['users', get(idAtom)],
  queryFn: async ({ queryKey: [, id] }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
    return res.json()
  },
}))

const UserData = () => {
  const [data] = useAtom(userAtom)
  return <div>{JSON.stringify(data)}</div>
}

atomWithInfiniteQuery

atomWithInfiniteQuery is very similar to atomWithQuery, however it creates an InfiniteQuery, which is used for data that is meant to be paginated. You can read more about Infinite Queries here. This atom supports all features you'd expect to find when using the standard react-query package.

Rendering lists that can additively "load more" data onto an existing set of data or "infinite scroll" is also a very common UI pattern. React Query supports a useful version of useQuery called useInfiniteQuery for querying these types of lists.

A notable difference between a standard query atom is the additional option getNextPageParam and getPreviousPageParam, which is what you'll use to instruct the query on how to fetch any additional pages.

import { useAtom } from 'jotai'
import { atomWithInfiniteQuery } from 'jotai/query'

const idAtom = atom(1)
const userAtom = atomWithInfiniteQuery((get) => ({
  queryKey: ['users', get(idAtom)],
  queryFn: async ({ queryKey: [, id] }) => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
    return res.json()
  },
  // infinite queries can support paginated fetching
  getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
}))

const UserData = () => {
  const [data] = useAtom(userAtom)
  return data.pages.map((userData, index) => <div key={index}>{JSON.stringify(userData)}</div>)
}

Fetching pages and refetching

Using the same atom as in the above example, we can use the update method returned from useAtom to call different react-query methods:

const UserData = () => {
  const [data, update] = useAtom(userAtom)
  
  const handleFetchNextPage = () => update({ type: 'fetchNextPage' })
  
  const handleFetchPreviousPage = () => update({ type: 'fetchPreviousPage' })
  
  const handleRefetchAllPages = () => update({ type: 'refetch' })
}

SSR support

Both atoms can be used within the context of a server side rendered app, such as a next.js app or gastby app. You can use both options that React Query supports for use within SSR apps, hydration or initialData.

Examples

Basic demo

Hackernews