React)pagination(with contextAPI+tailwind)

김명성·2022년 6월 3일
1
post-thumbnail

Pagination

업로드중..

  1. 버튼은 페이지네이션의 기준이 되는 숫자를 통해 생성된다.
    (ex : 10개씩 보여주어야 하고 총 67개가 있다면 7 페이지가 나와야 함. 변수 pageNumber 참조)
    버튼을 만들 때에는 Array 생성자함수, fill, map 메서드를 통해 생성한다.

  2. 버튼에게 클릭할 때마다 현재페이지의 값을 갖게 만드는 함수를 전달하고, 현재페이지는 Context API에 등록된 스테이트이며 해당 페이지넘버 스테이트는 API URL의 page를 제어하는 스테이트이다.(3번 참조)

  3. 67개를 10개씩 끊는다면 마지막 배열은 10이 아닌 7이다. 그 부분에 대한 에러핸들링 필요.


  1. Context API에 사용할 페이지넘버 제어 함수 작성.
import { useState } from "react";
import { createContext } from "react";

export const UtilContext = createContext({
  currentPageNumber: 0,
  getNewsOnPage: (number) => {},
  increasePageNumber: () => {},
  decreasePageNumber: () => {},
})


const UtilProvider = ({children}) => {
  const [currentPageNumber,setCurrentPageNumber] = useState(1)

  const getNewsOnPage = (number) =>{
    setCurrentPageNumber(number);
  }
  const increasePageNumber = () => {
    setCurrentPageNumber(prev => prev + 1);
  }
  const decreasePageNumber = () => {
    setCurrentPageNumber(prev => prev - 1);
  }

  const utilContext = {
    getNewsOnPage,
    increasePageNumber,
    decreasePageNumber,
    currentPageNumber
  }
  return <UtilContext.Provider value={utilContext}>{children}</UtilContext.Provider>
}


export default UtilProvider
  1. Route에 Context API Provider 감싸기.
// RouteBundle.jsx

      <Route path =":categories" element={
      <UtilProvider>
      <Categories/>
      </UtilProvider>} />
  1. Categories에 함수 풀기

import React, { useState } from 'react';
import { useContext } from 'react';
import { useEffect } from 'react';
import { useParams } from 'react-router-dom';
import CategoriesTemplete from '../components/CategoriesTemplete';
import useHttp from '../hooks/useHttp';
import { getHeadlineNews } from '../lib/api';
import { UtilContext } from '../store/UtilContext';



const Categories = () => {
  const {currentPageNumber} = useContext(UtilContext)
  const {sendRequest,status,data:categoryNews} = useHttp(getHeadlineNews);
  const {categories} = useParams();
  
  useEffect(()=>{
   sendRequest(categories,currentPageNumber);
   return () => sendRequest(categories);
  },[sendRequest,categories,currentPageNumber])
  
  if(status === 'pending'){
    return <div class="text-xl absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">Now Loading.........</div>
  }

  if(categoryNews === null ){
    return <div>something wrong!</div>
  }

  return <CategoriesTemplete  categories={categories} categoryNews={categoryNews} />
};

export default Categories;
  1. pagination에 getNewsOnPage 함수 풀기

import { useContext } from "react"
import { useState } from "react"
import { UtilContext } from "../store/UtilContext"
import PaginationView from "./PaginationView"

export default function Pagination({totalResults,articles,categories}) {
  const pageNumber = articles.length === 10 ? Math.ceil(totalResults / articles.length) : Math.ceil(totalResults / 10)
  const [page,setPage] = useState(1)
  const {getNewsOnPage} = useContext(UtilContext)
  
  return <PaginationView getNewsOnPage={getNewsOnPage} pageNumber={pageNumber} articles={articles} totalResults={totalResults} page={page} />
}

5.paginationView 컴포넌트에서 사용

import React from 'react';
import uuid from "react-uuid"

const PaginationView = ({pageNumber,totalResults,getNewsOnPage,page}) => {
  return (
    <div className="bg-slate-500 px-4 py-3 flex items-center justify-between rounded-md sm:px-6 absolute bottom-4">
    <div className="flex justify-between  sm:hidden ">
      <button
        href="#"
        className="relative inline-flex items-center shrink px-2 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
      
      >
        Previous
      </button>
      <button
        href="#"
        className="ml-3 relative inline-flex items-center px-5 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
      >
        Next
      </button>
    </div>
    <div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
      <div>
        <p className="text-sm text-primary pr-4">
          Showing <span className="font-medium">1</span> to <span className="font-medium">10</span> of{' '}
          <span className="font-medium">{totalResults}</span> results
        </p>
      </div>
      <div>
        <nav className="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination">
          <button
            href="#"
            className="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
          >
            <span className="sr-only">Previous</span>
            <div className="h-5 w-5 font-bold" aria-hidden="true"></div>
          </button>
          {/* create button */}
          {Array(pageNumber).fill().map((_,i) =>(<button
            key={uuid()}
            aria-current={page}
            className="z-10 bg-primary border-slate-300 text-primary relative inline-flex items-center px-4 py-2 border text-sm font-medium"
            onClick={()=>getNewsOnPage(i + 1)}
          >
            {i+1}
          </button>))}
         
          <button
            href="#"
            className="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
          >
            <span className="sr-only">Next</span>
            <div className="h-5 w-5 font-bold" aria-hidden="true"></div>
          </button>
        </nav>
      </div>
    </div>
  </div>
  );
};

export default PaginationView;

경로가 바뀔 때 다시 currentPageNumber를 초기화 해야한다.
예를들어, science section에서 4번페이지를 보고 있다가, sports section으로 이동할 때 아무 처리도 하지 않는다면 sports section으로 이동할 때 sports section의 4번 페이지로 이동하게 된다.

useLocation을 통해 pathname이 변경될 때마다 1로 값이 바뀌게 변경한다.

  const {pathname} = useLocation()
  useEffect(()=>{
    getNewsOnPage(1)
  },[pathname])

0개의 댓글