react
frontend
work-in-progress

Getting Started with React Query

Author: Joanna Piecuch

The problem

Each of us was once at the beginning of a project and wondered how to manage asynchronous data in an application. You probably know how annoying it could be to handle different states (loading, error), share data between components and keep the synchronized state in your components. So, let's overview React Query.

React Query - what is it?

React Query is a data management library. It makes fetching, caching, synchronizing and updating server state in your app.

Preparing React Query For Using

First we have to wrap our app with the provider.

const queryClient = new QueryClient();

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

root.render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  </React.StrictMode>
);

Fetching data

In the example below fetchCharacters is async method return an array with all characters. React Query provides us the useQuery hook to fetch and control state of data.

export const Characters = () => {
    const { isLoading, isError, data, error } = useQuery(['characters'],() => fetchCharacters());
}

The useQuery hook result contains some states, which can helpful to manage our app.

Pagination and infinity scroll

If we have very long list of elements, will be better use the pagination. We can do it in two ways.

  1. The first way is basic pagination. We pass a page parameter to our call API method. useQuery hook reacts on page changes.
export const Characters = () => {
  const [page, setPage] = useState(1);

  const { data, isLoading } = useQuery(['characters'], () =>
    fetchCharacters(page)
  );
}
  1. React Query provides us useInfiniteQuery hook which contains some methods to handle pagination in easy way.
export const CharactersInfinityScroll = () => {
  const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
    useInfiniteQuery(
      ['character-infinity'],
      ({ pageParam = 1 }) => fetchCharactersInfinity(pageParam),
      {
        getNextPageParam: (lastPage, allPages) => allPages.length + 1
      }
    );
}

Modifying data in the server

The second integral part to working with data is updating it. For this use-case, React Query provides us useMutation hook. useMutation is similar to useQuery. It tracks state of mutations and give us a loading and error status.

In the example below addCharacter is a async method to add new character to the list. Mutations update data in the server, but if we want to synchronize data in the app, we need to tell React Query: 'Hey, your data is invalid'. We can do it using invalidateQueries function. After that React Query automatically refetch data and update list.

export const CharacterUpdate = () => {
  const { characterId } = useParams();

  const addNewCharacter = useMutation((newCharacter: Character) =>
    addCharacter(newCharacter, characterId),
    {
      onSuccess: () => {
        queryClient.invalidateQueries(['characters'])
      }
    }
  );

  const onSubmit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const inputValue = new FormData(event.currentTarget).get('name');
    addNewCharacter.mutate(inputValue);
  };

  return (
    <form onSubmit={onSubmit}>
      <input name="name" placeholder="Character name" />
      <button type="submit">Add new character</button>
    </form>
  );
};

Devtools

React Query has a great devtools feature. It is separate package that you need to install:

npm i @tanstack/react-query-devtools

and then we have to add React Query Devtools to our app.

const queryClient = new QueryClient();

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

root.render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <ReactQueryDevtools initialIsOpen={false} />
      <App />
    </QueryClientProvider>
  </React.StrictMode>
);

Conclusion

React Query is a good server state management library to simplifying your data-fetching needs. It provides many features which save our time and help to keep clean and simply code. React Query as every solution has pros and cons.

Pros and cons of solution

Pros:

Cons: