1

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

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I didn’t really get the fetch part, could you please give an example, if possible? In general I wanted to know, whether I’m doing the right thing with page reloading or is there a way to navigate through pages by Link tags or any other way (without reloading). Because now I rewrote it, removed onClick method, added <Link to={/events/page=${number}}\> and it changes url but not renders the page.
In the array of your useEffect() (which is currently just []), put in the page number so that it's [props.match.params.page]. Your useEffect() will re-execute every time that prop changes, and therefore when the page changes, you'll fetch the data again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.