Back

Fetching and Updating Data with React Query

Fetching and Updating Data with React Query

React Query is often described as the missing data-fetching library for React. Still, in more technical terms, it makes fetching, caching, synchronizing, and updating server state in your React applications a breeze. It provides a Hook for fetching, caching, and updating asynchronous data in React without touching any “global state” like Redux. Initially, it seems like a simple library; however, it is packed with complex features which handle most of the server state management issues you might have in an application.

In this article, we will discuss using React Query in React applications, and learn how to fetch and update a list of users from a database. Let’s get started!

Why do you need React Query?

React Query is hands down one of the best libraries for managing server states. It works amazingly well out-of-the-box, with zero-config, and can be customized to your liking as your application grows.

If this is the first time you will come across React Query, I guarantee you are walking out of this article with one of the best tools you will use for data fetching. You can agree with the sentiment that data fetching in React sucks. You try many hooks or even come out with a solution of yours, and it seems like you are always returning to the same loophole.

For instance, when working with an API, you have many things you want to track, like loading state and data state. While most traditional state management libraries are great for working with client states, they are not so great at working with async or server states.

Once the server state in your application is gotten, more issues could arise as you go. For example:

  • Caching data
  • Updating data
  • Lazy loading data
  • Knowing when data is “out of date”
  • Managing server state

React Query allows you to defeat and overcome the tricky challenges and hurdles of server state and control your app data before it starts to control you. On a more technical note, React Query will likely:

  • Help you erase a bunch of unneeded lines of code
  • Enable advanced maintainability
  • Have a direct impact on your end-users or site visitors by making your application speedier and more reactive.
  • Increase memory performance

In this article, we will explain data fetching and updating using the useQuery and useMutation hooks. Let’s get a project started.

Setting up our project

We’ll work with React version 18, Node, and Axios. To start the project, do:

npx create-react-app react-query
npm install react-query axios

To set up React-Query in a React application, there is a need to wrap the App.js component with the QueryClientProvider component from React-query, which will give us access to all the hooks from react-query. (This is because all our data fetching will be done there.) To start, we will replace our *index.js* file with the below code:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

import { QueryClient, QueryClientProvider } from "react-query";

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

const queryClient = new QueryClient();
root.render(
    <QueryClientProvider client={queryClient}>
    <App />
</QueryClientProvider>
);
    
reportWebVitals();

After setting up the development area, clear the returned JSX in App.js.

import './App.css';
function App() {
    return (
    <div className="App">
    <h1>React Query</h1>
    </div>
    );
}
    
export default App;

We are ready; let’s see how to fetch data.

Fetching Data with the useQuery hook

I will work you through the steps of fetching data from an API. The use-query is part of the React Query logic that prevents you from using the useEffect hook from React. If you are familiar with data fetching in React, you know that the useEffect can be used to fetch data and reload the page. The difference between React-Query and the useEffect is that React-Query will initially return the previously fetched data and then re-fetch.

const { isLoading, isFetching, error, data, status } = useQuery();

This makes our code a lot simpler and easy to maintain, as aforementioned. We will fetch a list of names from a public API (JSONPLACEHOLDER) by using Axios. We need to follow these steps:

  • Create a FetchApi.js file, where you will create an Asynchronous function that fetches the data from the base URL using Axios, then we export and import it into our main App.js

  • Use React Query to make API calls. First, we import UseQuery from React-query; here is how we use it in our component

const { isLoading, isFetching, error, data, status } = useQuery();

The isLoading displays while the Async-function runs, and we throw an error if there is one. The useQuery() will return two arguments, the first one is a unique key to differentiate what is being fetched from our API, and the second is Async-function from our FetchApi.js

  • Return a response: the data (names of users)

  • Inside the JSX, we return a list of names by mapping through the users

//FetchApi.js

import axios from "axios";
    
async function fetchPosts() {
    const { data } = await axios.get('https://jsonplaceholder.typicode.com/users')
    return data
}
    
export default fetchPosts;
//Ap.js

import React from 'react'
import { useQuery } from 'react-query'
import fetchPosts from './FetchApi';
import './App.css';
    
function App() {
    const { data, error, isError, isLoading } = useQuery('users', fetchPosts)
    
    if (isLoading) {
        return <div>Loading...</div>
    }
    if (isError) {
        return <div>Error! {error.message}</div>
    }
    
    return (
        <div className=''>
            <h1 className='container'>Users Name</h1>
            {
                data.map((users, id) => {
                    return <li className='container' key={id}>{users.name}</li>
                })
            }
    
        </div>
    )
}
    
export default App;

We’ll have some (very, very basic!) styling.

//styles

.container {
    display: flex;
    align-items: center;
    justify-content: center;
}

Here is what we have after fetching ;

Fetching names

Supposedly, if we take off the *fetchpost* from amongst the arguments passed in useQuery, we will get an error; this shows the error was also cached.

Open Source Session Replay

OpenReplay is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data.

replayer.png

Start enjoying your debugging experience - start using OpenReplay for free.

Updating server data using the useMutation hook

React Query needs a function that will return a promise, and in this section of the article we will be looking at how to make a post request. For the past headings, we have focused on the data fetching aspect of React Query. Now we will focus on data posting: sending data from your application to the backend. Let’s see how simple this is with React Query.

  • We will need to create a component called Form.js

  • We will use the useMutation() hook, which returns an isLoading, error, and mutate function that will be used to make requests and enfold values while requests are made. It also has an Asynchronous function as an argument. The isLoading and error handle the mutation function as they are displayed during the API call process.

  • We will create an Async-Function called createName which will make HTTP POST requests using the Axios library to the API(https://jsonplaceholder.typicode.com/users)

  • We will import the useState() hook to update the state of the input elements.

import React, { useState } from 'react';
import { useMutation } from 'react-query';
import axios from 'axios';
import './App.css';
    
const Form = () => {
    
    const [name, setName] = useState('')
    const [message, setMessage] = useState('')
    
    const { isLoading, isError, error, mutate } = useMutation(createName)
    
    
    async function createName() {
        const response = await axios.post('https://jsonplaceholder.typicode.com/users')
        setMessage(response.data)
    }
    
    const onChange = (e) => {
        setName(e.target.value)
    }
    
    const Create = () => {
        mutate({ id: Date.now(), name })
    }
    
    return (
        < >
            <div className="">
                <h1>Name</h1>
                <label>List of Names:</label>
                <input type="text"
                    value={name}
                    onChange={onChange} />
                <button onClick={Create} >Create</button>
                <p> Created a new Name ID: {message && message.id}</p>
    
                <div className=''>
                    {isLoading
                        ? "updating..." : ""
                    }
                    {
                        isError
                            ? error.message : ""
                    }
                </div>
            </div>
    
        </>
    )
    
}
    
export default Form;

We can now import this component to our main App.js component.

import React from 'react'
import { useQuery } from 'react-query'
import fetchdata from './FetchApi';
import './App.css';
import Form from './form';
    
function App() {
    
    const { data, error, isError, isLoading } = useQuery('users', fetchdata)
    
    if (isLoading) {
        return <div>Loading...</div>
    }
    if (isError) {
        return <div>Error! {error.message}</div>
    }
    
    return (
        <div className=''>
            <h1 className=''>Users Name</h1>
            {
                data.map((users, id) => {
                    return <ul>
                        <li className='' key={id}>{users.name}</li>
                    </ul>
                })
            }
            <Form />  <--------imported//
    
        </div>
    )
}
    
    
export default App;

We have this:

Posting names

If you counted earlier, you noticed there are ten names in ten IDs. Using the useMutation() hook, we have been able to make a post request and get the name updated to 11.

Conclusion

As we build applications and get to their complexity, maintaining our server state of different API endpoints becomes difficult. React Query helps manage data requests, making our application maintainable.

Reference