How to display posts on the current page from the API

I’m getting data from Django Rest API and React for Frontend, and I need to create the pagination with posts. I did it all in pagination component. I created the state with current page and I’m changing it by clicking on the page button in component like this:

const Paginator = () => {

  const [count, setCount] = useState(null);
  const [currentPage, setCurrentPage] = useState(1);
  const [totalPages, setTotalPages] = useState(null);
  const [nextPage, setNextPage] = useState(null);
  const [previousPage, setPreviousPage] = useState(null);
  const [valid, setValid] = useState(false);

  useEffect(() => {
    fetch(`http://127.0.0.1:8000/api/software/?p=${currentPage}`)
        .then(response => response.json())
        .then(data => {
          setCount(data.count);
          setTotalPages(data.total_pages)
          setNextPage(data.links.next);
          setPreviousPage(data.links.previous);
          setValid(true);
        })
  }, [currentPage]);

  ...

  return (
    <>
    {
      ...
      <PbStart style={style} totalPages={range(1, totalPages+1)} setCurrentPage={setCurrentPage} />
      ...
    }
    </>
  );
};

const PagItem = ({key, handleClick, className, title, name }) => {
  return (
    <li key={key} onClick={handleClick}>
      <Link to='/' className={className} title={`Go to page ${title}`}>
        {name}
      </Link>
    </li>
  );
};

const PbStart = ({ style, totalPages, setCurrentPage }) => {
  return (
    ...
      {totalPages.map(p => (
        <PagItem key={p} handleClick={() => setCurrentPage(p)} title={p} name={p} />
      ))}
    ...
  );
};

And in posts component I don’t know how to change current page, or getting it from the paginaton component. I’ve written that like this:

const Softwares = () => {

  const [softwares, setSoftwares] = useState([]);
  const [currentPage, setCurrentPage] = useState(1);
  const [valid, setValid] = useState(false);

  useEffect(() => {
    fetch(`http://127.0.0.1:8000/api/software/?p=${currentPage}`)
        .then(response => response.json())
        .then(data => {
          setSoftwares(data.results);
          setValid(true);
        })
  }, [currentPage]);

  return (
    <>
    {
      ...
      {softwares.map(s => (
        <Article key={s.id} pathname={s.id} title={s.title} image={s.image} pubdate={s.pub_date} icon={s.category.parent.img} categoryID={s.category.id} categoryName={s.category.name} dCount={s.counter} content={s.content} />
      ))}
      ...
    }
    </>
  );
};

So, how to do that(get the current page from pagination component or another way)?

Answer

I think a Paginator’s job is only moving between pages and updating current page state. It should not be fetching data by itself, you can provide functionality to do extra work with props.

I haven’t tested this, but this might be a good starting point.

With the example below you’ll have a list of articles and then below it next and previous buttons.

In Softwares, as you can see I am passing the same function for handling next and previous pages, you can refactor it to have one function like onPageMove and call this function handleNext and handlePrev. I added two separate functions if you have want to handle something different in either.

const Paginator = ({
    total, // Required: Total records
    startPage = 1, // Start from page / initialize current page to
    limit = 30, // items per page
    onMoveNext = null, // function to call next page,
    onMovePrev = null, // function to call previous page
}) => {
  const [currentPage, setCurrentPage] = useState(startPage);

  const canGoNext = total >= limit;
  const canGoPrev = currentPage > 1;

  function handleNext(e) {
    if (canGoNext) {
      setCurrentPage((prevState) => prevState+1);
      onMoveNext && onMoveNext({ currentPage });
    }
  }

  function handlePrev(e) {
    if (canGoPrev) {
      setCurrentPage((prevState) => prevState-1);
      onMovePrev && onMovePrev({ currentPage });
    }
  }

  return (
    <div>
      <button onClick={handlePrev} disabled={!canGoPrev}>Prev</button>
      <button onClick={handleNext} disabled={!canGoNext}>Next</button>
    </div>
  );
};

Here is how you can use Paginator in other components.

const PER_PAGE = 30; // get max # of records per page
const Softwares = () => {
  const [softwares, setSoftwares] = useState([]);
  const [valid, setValid] = useState(false);

  const onFetchData = ({ currentPage }) => {
    fetch(`http://127.0.0.1:8000/api/software/?p=${currentPage}&per_page=${PER_PAGE}`)
      .then(response => response.json())
      .then(data => {
        setSoftwares(data.results);
        setValid(true);
      })
  }

  useEffect(() => {
    onFetchData({ currentPage: 1 })
  }, []);

  return (
    <>
      {softwares.map(s => (
        <Article key={s.id} pathname={s.id} title={s.title} image={s.image} pubdate={s.pub_date} icon={s.category.parent.img} categoryID={s.category.id} categoryName={s.category.name} dCount={s.counter} content={s.content} />
      ))}
      <Paginator total={softwares.length} limit={PER_PAGE} onMoveNext={onFetchData} onMovePrev={onFetchData} />
    </>
  );
};