페이지 매김 추가

ExamPro 마크다운 랩 파트 2



이것은 ExamPro Next.js 과정의 일부입니다. 페이지 매김 및 작업 유형 필터링과 같은 추가 콘텐츠가 이 실습에 추가됩니다.

이 실습에서는 기존 애플리케이션에 페이지 매김 기능을 추가합니다.

페이지네이션 기능 추가


http://localhost:3000/jobs는 다음과 같습니다.



구성 파일



이 파일은 한 페이지에 표시할 작업 수를 설정하는 데 사용됩니다.
  • 만들기 ./config/index.js

  • export const JOBS_PER_PAGE = 4;
    


    페이지네이션 컴포넌트


  • 만들기 ./components/jobs/Pagination.js

  • import Link from 'next/link';
    
    import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid';
    
    import { JOBS_PER_PAGE } from '@/config/index';
    
    export default function Pagination({ currentPage, numJobs, numPages }) {
      const isFirst = currentPage === 1;
      const isLast = currentPage === numPages;
      const prevPage = `/jobs/page/${currentPage - 1}`;
      const nextPage = `/jobs/page/${currentPage + 1}`;
      const firstJobOfPage = parseInt((currentPage - 1) * JOBS_PER_PAGE + 1);
      const lastJobOfPage = parseInt(currentPage * JOBS_PER_PAGE);
    
      if (numPages === 1) return <></>;
    
      return (
        <div className="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6">
          <div className="flex-1 flex justify-between sm:hidden">
            {/* If not first page, display the Previous link */}
            {!isFirst && (
              <Link href={prevPage}>
                <a className="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
                  Previous
                </a>
              </Link>
            )}
    
            {/* If not last page, display the Next link */}
            {!isLast && (
              <Link href={nextPage}>
                <a className="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
                  Next
                </a>
              </Link>
            )}
          </div>
    
          <div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
            <div>
              <p className="text-sm text-gray-700">
                Showing <span className="font-medium">{firstJobOfPage}</span> to{' '}
                <span className="font-medium">{lastJobOfPage > numJobs ? numJobs : lastJobOfPage}</span>{' '}
                of <span className="font-medium">{numJobs}</span> results
              </p>
            </div>
            <div>
              <nav
                className="relative z-0 inline-flex rounded-md shadow-sm -space-x-px"
                aria-label="Pagination"
              >
                {/* If not first page, display the Previous link */}
                {!isFirst && (
                  <Link href={prevPage}>
                    <a 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>
                      <ChevronLeftIcon className="h-5 w-5" aria-hidden="true" />
                    </a>
                  </Link>
                )}
    
                {/* Loop through numPages array */}
                {Array.from({ length: numPages }, (_, i) => (
                  <li key={i} className="list-none">
                    <Link href={`/jobs/page/${i + 1}`} passHref>
                      {i == currentPage - 1 ? (
                        <a
                          aria-current="page"
                          className="z-10 bg-orange-50 border-orange-400 text-orange-500 relative inline-flex items-center px-4 py-2 border text-sm font-medium"
                        >
                          {i + 1}
                        </a>
                      ) : (
                        <a className="bg-white border-gray-300 text-gray-500 hover:bg-gray-50 relative inline-flex items-center px-4 py-2 border text-sm font-medium">
                          {i + 1}
                        </a>
                      )}
                    </Link>
                  </li>
                ))}
    
                {/* If not last page, display the Next link */}
                {!isLast && (
                  <Link href={nextPage}>
                    <a 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>
                      <ChevronRightIcon className="h-5 w-5" aria-hidden="true" />
                    </a>
                  </Link>
                )}
              </nav>
            </div>
          </div>
        </div>
      );
    }
    


    페이지 매김을 추가하려면 작업 목록에 대한 새로운 동적 경로가 필요합니다.
  • 생성pages/jobs/page/[page_index].js 파일
  • fs 및 경로 모듈 가져오기
  • 수입품
  • 가져오기 작업 구성 요소
  • 레이아웃 구성 요소 가져오기
  • 페이지 매김 가져오기

  • import { promises as fs } from 'fs';
    import path from 'path';
    import matter from 'gray-matter';
    
    import { JOBS_PER_PAGE } from '@/config/index';
    
    import Job from '@/components/jobs/Job';
    import Layout from '@/components/Layout';
    import Pagination from '@/components/jobs/Pagination';
    


  • getStaticPaths() 함수 생성

  • export async function getStaticPaths() {
      // Read from the /jobs directory
      const files = await fs.readdir(path.join('jobs'));
      // Get the number of files and divide by JOBS_PER_PAGE then round up
      const numPages = Math.ceil(files.length / JOBS_PER_PAGE);
    
      let paths = [];
    
      for (let i = 1; i <= numPages; i++) {
        paths.push({
          params: { page_index: i.toString() },
        })
      }
    
      return {
        paths,
        fallback: false,
      }
    }
    


  • getStaticProps() 함수 생성

  • export async function getStaticProps({ params }) {
      const page = parseInt((params && params.page_index) || 1);
    
      // Read from /jobs directory
      const files = await fs.readdir(path.join('jobs'));
    
      // Map through jobs directory
      const jobs = files.map(async (filename) => {
        // Set 'slug' to name of md file
        const slug = filename.replace('.md', '');
        // Read all markdown from file
        const markdown = await fs.readFile(path.join('jobs', filename), 'utf-8');
        // Extract data from markdown
        const { data } = matter(markdown);
    
        // return slug and data in an array
        return {
          slug,
          data,
        };
      });
    
      // Get total number of jobs
      const numJobs = files.length;
      // Get the number of files and divide by JOBS_PER_PAGE then round up
      const numPages = Math.ceil(files.length / JOBS_PER_PAGE);
      // Get the page index
      const pageIndex = page - 1;
      // Display only the number of jobs based on JOBS_PER_PAGE
      const displayJobs = jobs.slice(pageIndex * JOBS_PER_PAGE, (pageIndex + 1) * JOBS_PER_PAGE);
    
      return {
        props: {
          jobs: await Promise.all(displayJobs),
          numJobs,
          numPages,
          currentPage: page,
        },
      };
    }
    


  • JobPostings() 함수 생성

  • export default function JobPostings({ jobs, numJobs, numPages, currentPage }) {
      return (
        <Layout title="Jobs | ExamPro">
          <div className="px-4 py-4 sm:px-6 md:flex md:items-center md:justify-between">
            <div className="flex-1 min-w-0">
              <h2 className="text-2xl font-bold leading-7 text-gray-900 sm:text-3xl sm:truncate">
                Job Postings
              </h2>
            </div>
          </div>
          <div className="bg-white my-4 shadow overflow-hidden divide-y divide-gray-200 sm:rounded-md">
            <ul role="list" className="divide-y divide-gray-200">
              {/* Maps through each job */}
              {jobs.map((job, index) => (
                <Job key={index} job={job} />
              ))}
            </ul>
          </div>
          <Pagination currentPage={currentPage} numJobs={numJobs} numPages={numPages} />
        </Layout>
      );
    }
    


  • pages/jobs/index.jspages/jobs/page/[page_index.js] 에서 대부분 동일한 기능을 사용하므로 다음과 같이 pages/jobs/index.js 가져오기에서 모든 항목을 삭제할 수 있습니다.

  • import { getStaticProps } from './page/[page_index]';
    import JobPostings from './page/[page_index]';
    
    export { getStaticProps };
    export default JobPostings;
    

    좋은 웹페이지 즐겨찾기