Mastering React Query: Fetching Data and Managing States Efficiently

Mastering React Query: Fetching Data and Managing States Efficiently

Fetching and managing data from the server is a common task in modern web applications. Developers usually use useEffect and useState hooks to fetch the data and manage the component state, but these tools often result in complex and repeated code.?

This is where React Query (also known as Tanstack Query) comes into the picture. React Query makes it easy to fetch, cache, and synchronise the data with minimum effort, allowing developers to focus on their application logic. It reduces boilerplate, improves performance, and enhances user experience, making it a go-to library for managing server state in React applications.

In this article, we’ll see how to use React Query to fetch data from the server using useQuery and handle loading, error and success state more effectively.?


Why Should We Use React Query?

React Query offers various advantages over traditional data-fetching approaches like useEffect and useState hooks. Let’s have a look at why should we consider it:?

  • Simplified Data Fetching

React Query simplifies the complexities of fetching, caching and updating the data so we don’t need to manage the isLoading or isError flags manually.

  • Automatic Caching

React Query caches the fetched data by default. This means that the subsequent requests for the same data can be served from the stored cache, which results in improving the performance.

  • Background Updates

React Query always ensures that the Application always has updated data by automatically refetching the outdated queries in the background.

  • Granular Control

React Query provides options to control how and when the data is prefetched, for example focusing on the window, reconnection of the network or at specific time intervals.

  • Built-in State management

React Query handles the loading, success and error state on its own, So you can fully focus on rendering your UI.

  • Optimistic Updates

React Query allows you to update the UI before a mutation is confirmed by the server, creating a smooth user experience.

  • Easy Debugging

With tools like React Query Devtools, debugging and monitoring queries become easy.


Setting up React Query

Let’s set up React Query in our React Application

  • Install React Query

npm install @tanstack/react-query

or 

yarn add @tanstack/react-query        

  • Install React Query Devtools (optional)

npm install @tanstack/react-query-devtools

or 

yarn add @tanstack/react-query-devtools        

  • Wrapping the Application with QueryClientProvider

We need to wrap our App with the QueryClientProvider component to connect and provide a QueryClient to our application.

import React from "react";
import ReactDOM from "react-dom";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import App from "./App";

const queryClient = new QueryClient();

ReactDOM.render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>,
  document.getElementById("root")
);        

The setup is done now we can start fetching the data ??


Fetching Data with useQuery

We will create a simple Application to fetch and render the data from a public API. In this article, we will use JSONPlaceholder API to fetch and show the list of posts.?

  • Fetch Data

Create a function to fetch the data from API:?

const fetchPosts = async () => {
  const response = await fetch("https://jsonplaceholder.typicode.com/posts");
  if (!response.ok) {
    throw new Error("Network response was not ok");
  }
  return response.json();
};        

Now import the useQuery hook to fetch the data:

import React from "react";
import { useQuery } from "@tanstack/react-query";

const Posts = () => {
  const { data, isLoading, isError, error } = useQuery(["posts"], fetchPosts);

  if (isLoading) {
    return <p>Loading...</p>;
  }

  if (isError) {
    return <p>Error: {error.message}</p>;
  }

  return (
    <div>
      <h1>Posts</h1>
      <ul>
        {data.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default Posts;        

Understanding the Code

useQuery Parameters:

  • Key: The first parameter, ["posts"], is the query key. It uniquely identifies this query and is used for caching and refetching.
  • Fetch Function: The second parameter is the function (fetchPosts) that fetches the data.

Returned Values:

  • data: Contains the fetched data when the query is successful.
  • isLoading: A boolean indicating if the query is in the loading state.
  • isError: A boolean indicating if the query encountered an error.
  • error: Contains the error object if the query fails.

Handling States:

  • Loading State: Render a loading spinner or message while data is being fetched.
  • Error State: Display an error message if the fetch fails.
  • Success State: Render the fetched data.


Enhancing the User Experience

React Query offers many features to improve the user experience further.

Stale Data and Background Updates

React Query caches data, so it doesn’t refetch unnecessarily. However, it ensures the data is always fresh by fetching it in the background. You can configure how React Query manages this with the staleTime and refetchOnWindowFocus options.

const { data, isLoading, isError, error } = useQuery(["posts"], fetchPosts, {
  staleTime: 5000, // Cache data for 5 seconds
  refetchOnWindowFocus: false, // Do not refetch when the window regains focus
});        

Error Handling with Fallback UI

For finer error handling, you can show a retry button or a fallback UI.

if (isError) {
  return (
    <div>
      <p>Error: {error.message}</p>
      <button onClick={() => refetch()}>Retry</button>
    </div>
  );
}        

React Query Devtools

For better debugging and monitoring your queries, you can use React Query Devtools. Add the following code to your app:

import { ReactQueryDevtools } from "@tanstack/react-query-devtools";

<QueryClientProvider client={queryClient}>
  <App />
  <ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>;        

This will give you deep insights about your queries, cache, and background updates.


Final Code

Here’s the complete code:

import React from "react";
import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";

// Query Client
const queryClient = new QueryClient();

// Fetch Function
const fetchPosts = async () => {
  const response = await fetch("https://jsonplaceholder.typicode.com/posts");
  if (!response.ok) {
    throw new Error("Network response was not ok");
  }
  return response.json();
};

// Posts Component
const Posts = () => {
  const { data, isLoading, isError, error, refetch } = useQuery(["posts"], fetchPosts, {
    staleTime: 5000,
    refetchOnWindowFocus: false,
  });

  if (isLoading) {
    return <p>Loading...</p>;
  }

  if (isError) {
    return (
      <div>
        <p>Error: {error.message}</p>
        <button onClick={() => refetch()}>Retry</button>
      </div>
    );
  }

  return (
    <div>
      <h1>Posts</h1>
      <ul>
        {data.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
};

// App Component
const App = () => {
  return (
    <QueryClientProvider client={queryClient}>
      <Posts />
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
};

export default App;        

Conclusion

In this article, we learned about how to use React Query to fetch the data from the server and handle it on the front end.

React Query simplifies data fetching and state management in React apps. With features like caching, background updates, and built-in support for loading and error states, it reduces boilerplate code and enhances performance.

By combining useQuery with proper loading and error handling, you can create user-friendly and efficient applications with ease. Give it a try in your next project!


要查看或添加评论,请登录

Devesh Lashkari的更多文章

社区洞察

其他会员也浏览了