skip to Main Content

I am using React Query to practice fetching data and displaying them in the UI. I have a JSON server that serves an array of colors with an id and a label. I want to use pagination to display only 2 colors at a time and a next button to move to the next page. I am using axios to make the API requests and passing the page number as a query parameter.

However, when I click the next button, the data is not updating and the UI shows the same colors as before. The query string for the page number is not updating the information of the next page. I don’t know why this is happening and how to fix it.

Here is the code from the JSON server:


 "colors": [
      {
        "id": 1,
        "label": "red"
      },
      {
        "id": 2,
        "label": "blue"
      },
      {
        "id": 3,
        "label": "green"
      },
      {
        "id": 4,
        "label": "yellow"
      },
      {
        "id": 5,
        "label": "black"
      },
      {
        "id": 6,
        "label": "white"
      },
      {
        "id": 7,
        "label": "orange"
      },
      {
        "id": 8,
        "label": "purple"
      }
    ]

Here is my code:

import { useState, useEffect } from "react";
import axios from "axios";

import { useQuery } from "react-query";



const Color = () => {
const Feachcolor = (addpage) => {
    return axios.get(`http://localhost:8000/colors?_limit=2&_page=${addpage}`)
};

const [showcolor, useshowcolor] = useState(false);

const Handleshow = () => {
useshowcolor(true)
}
const [addpage, useaddpage] = useState(1)

const Addpagecontrol = () => {
useaddpage(prevPage => prevPage + 1)
};

console.log(addpage)

const {data, isLoading, isError, error} = useQuery(["colors", addpage], () => Feachcolor(addpage))
 

if (isError) {
    return <h2>{error.message}</h2>
}

if (isLoading) {
    return <div>loading...</div>
}
    return ( <>
   
    {data && data?.data.map((color) => {
      return  (<div key={color.id}>
            <h6><span>{color.id}</span> - {color.label}</h6>
        </div>)
    }) }
    <button onClick={Handleshow}>show color</button>
    {showcolor && <>
    
    <button onClick={() => useaddpage(page => page - 1)} disabled={addpage === 1}>prev</button>
    <button onClick={Addpagecontrol} disabled={addpage === 4}>next</button>  
    </>
    }
    </> 
    
    );
}
 
export default Color;

The expected output is that the UI should show the next 2 colors when I click the next button, and the query string should change accordingly. For example, if I start with http://localhost:8000/colors?_limit=2&_page=1, I should see red and blue, and when I click the next button, the URL should change to http://localhost:8000/colors?_limit=2&_page=2 and I should see green and yellow.

The actual output is that the UI shows the same colors as before, and the query string does not change. For example, if I start with http://localhost:8000/colors?_limit=2&_page=1, I see red and blue, and when I click the next button, the URL stays the same and I still see red and blue.

I am using React Query version 3.34.0, axios version 0.24.0, and React version 17.0.2.

I have tried to use the keepPreviousData option in the useQuery hook, but it did not make any difference. I have also tried to console.log the data and the page number, but they seem to be correct.

I would appreciate any help or suggestions on how to solve this problem. Thank you.

2

Answers


  1. The problem is the way you’re managing the state of the page number (addpage).

    The addpage state is being updated asynchronously when you call useaddpage(prevPage => prevPage + 1), but the useQuery hook is already using the old value of addpage to fetch data when it runs.

    First I would rename addpage to ‘currentPage’

    const [currentPage, setCurrentPage] = useState(1); 
    

    And then I would include these two functions to handle the values of the current page.

    const handleNextPage = () => {
        setCurrentPage((prevPage) => prevPage + 1); 
    };
    
    const handlePrevPage = () => {
        setCurrentPage((prevPage) => Math.max(prevPage - 1, 1));
    };
    

    And then you can call these inside your on click:

    <button onClick={handlePrevPage} disabled={currentPage === 1}> 
    
    <button onClick={handleNextPage} disabled={data.data.length < 2}>
    
    Login or Signup to reply.
  2. I have changed functions Namings and Functional Updates for state change

    import { useState } from "react";
    import axios from "axios";
    import { useQuery } from "react-query";
    
    const Color = () => {
      const fetchColor = (addpage) => {
        return axios.get(`http://localhost:8000/colors?_limit=2&_page=${addpage}`);
      };
    
      const [showColor, setShowColor] = useState(false);
      const [addPage, setAddPage] = useState(1);
    
      const handleShow = () => {
        setShowColor(true);
      };
    
      const addPageControl = () => {
        setAddPage((prevPage) => prevPage + 1);
      };
    
      console.log(addPage);
    
      const { data, isLoading, isError, error } = useQuery(["colors", addPage], () =>
        fetchColor(addPage)
      );
    
      if (isError) {
        return <h2>{error.message}</h2>;
      }
    
      if (isLoading) {
        return <div>loading...</div>;
      }
    
      return (
        <>
          {data &&
            data?.data.map((color) => (
              <div key={color.id}>
                <h6>
                  <span>{color.id}</span> - {color.label}
                </h6>
              </div>
            ))}
          <button onClick={handleShow}>show color</button>
          {showColor && (
            <>
              <button onClick={() => setAddPage((page) => page - 1)} disabled={addPage === 1}>
                prev
              </button>
              <button onClick={addPageControl} disabled={addPage === 4}>
                next
              </button>
            </>
          )}
        </>
      );
    };
    
    export default Color;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search