eogenio777
eogenio777

Reputation: 65

How should I write Pagination component React JS?

I am building a web-app and I am also new with web-dev and all. I have backend-response as json with pagination in it, looks like that:

{
    "count": 16,
    "next": "http://localhost:8000/en/api/events/?page=3",
    "previous": "http://localhost:8000/en/api/events/",
    "results": [
        {
            "url": "",
            "id": ,
            "title": "",
            "creation_date": "",
            "description": "",
            "event_date": "",
            "link": ""
        },
        ...
    ],
    "total_pages": 4
}

And I want to add pagination to my EventList.jsx component:

import React, { useState, useEffect } from "react";
import { Link, NavLink } from "react-router-dom";
import "./Content.css";
import "./Pagination";

import { useLanguage } from "../../context/LanguageTranslator";
import { getLanguage } from "../../utils/getLanguage";
import Pagination from "./Pagination";

const initialState = {
  fullAPI: {
    count: 0,
    next: null,
    previous: null,
    results: [],
    total_pages: 0,
  },
};


const EventList = (props) => {
  const { language } = useLanguage();
  const currentLanguage = getLanguage(language);

  const [state, setState] = useState(initialState);
  const [loading, setLoading] = useState(false);

  useEffect(async () => {
    try {
      setLoading(true);
      const langUrl = currentLanguage.urlName;
      const page = props.match.params.page;
      const defaultUrl = `http://localhost:8000/${langUrl}/api/events/?page=${page}`;
      // * url which we will fetch
      let currentUrl;

      currentUrl = defaultUrl;

      const res = await fetch(currentUrl);
      const fullAPI = await res.json();

      setState((prevState) => ({ ...prevState, fullAPI }));
      setLoading(false);
    } catch (error) {
      setLoading(false);
      console.log(error);
    }
  }, []);

  const renderEvents = () => {
    const eventsList = state.fullAPI.results;

    return eventsList.map((item) => (
      <li key={item.id}>
        <p>
          {currentLanguage.title}:{item.title}
        </p>
        <p>
          <a href={item.link} className="aa">
            {currentLanguage.organizers}
          </a>
        </p>
        <Link to={`/events/id=${item.id}`} className="aa">
          {currentLanguage.linkToEvent}
        </Link>
      </li>
    ));
  };

  return (
    <main>
      <div>
        <ul>{renderEvents()}</ul>
        <Pagination
          totalPages={state.fullAPI.total_pages}
          next={state.fullAPI.next}
          previous={state.fullAPI.previous}
          currentPage={props.page}
        />
      </div>
    </main>
  );
};

export default EventList;

Basically now I have this Pagination.jsx:

import React, { useState, useEffect } from "react";
import { Link, NavLink, Redirect, useHistory } from "react-router-dom";
import "./Content.css";
import "./pagination.css";

const Pagination = (props) => {
  // * pagination

  const pages = [];
  for (let i = 1; i <= props.totalPages; ++i) {
    pages.push(i);
  }

  const handleClick = (number) => {
    return `/events/page=${number}`;
  };

  const renderPageNumbers = pages.map((number) => {
    return (
      <li
        key={number}
        id={number}
        onClick={() => {
          window.location.href = handleClick(number);
        }}
      >
        {number}
      </li>
    );
  });

  return (
    <div>
      {props.currentPage}
      <ul className="pageNumbers">{renderPageNumbers}</ul>
    </div>
  );
};

export default Pagination;

A coded it this way because I needed to reload page in order to fetch a response from server. So now I reload page and have no ability to store state inside the Pagination component and can't do things like this: [frist] [prev] 1 [2] ... 9 10 [next] [last]

only this: 1 2 3 4 5 6 7 8 9 10

Upvotes: 1

Views: 335

Answers (1)

DemiPixel
DemiPixel

Reputation: 1881

You should not only fetch a response from the server on page load. You can initially fetch on page load, but loading from the server should be in a separate function that's both called from within useEffect as well as when the user wants to go to the next or previous page.

As for the [first] [prev] kind of thing, you'll need to add separate elements for that. You're currently creating an array of every page--instead you probably just want to have individual elements for [first] [prev], [n-2] through [n+2], [next], and [last]. I notice your response has next and previous links, but, if possible, you're probably better off just sending the current page and then fetching the previous or next page number yourself (since you already know the endpoint to hit).

Anyway, I did my best, it didn't seem like you gave a specific question so I tried to answer what it looks like you were having trouble with.

Upvotes: 1

Related Questions