Pagination(product page)

김종민·2022년 8월 14일
0

apple-market

목록 보기
26/37


product page에서 pagination을 구현해 본다.
home page인 product page만 구현해 보고,
나머지 page에서는 시간 될때, 구현해 본다.

1. pages/api/product/index.ts

import withHandler, { ResponseType } from '@libs/server/withHandler'
import { NextApiRequest, NextApiResponse } from 'next'
import client from '../../../libs/server/client'
import { withApiSession } from '@libs/server/withSession'

async function handler(
  req: NextApiRequest,
  res: NextApiResponse<ResponseType>
) {
  if (req.method === 'GET') {
    const {
      query: { page, limit }, ///req.query에서 page와
                              ///limit를 받아옴.
                              ///page는 현재page
                              ///limit는 한페이지에 나타낼 갯수
    } = req
    const products = await client.product.findMany({
      include: {
        _count: {
          select: {
            favs: true,
          },
        },
      },
      take: Number(limit), ///한페이지에 나타낼 갯수
      skip: (Number(page) - 1) * Number(limit),
      ///다음 페이지에 나타낼 item의 갯수 
      
      orderBy: { createdAt: 'asc' }, ///item 정렬순서
      ///desc 최신것부터,  asc 옛날거부터~
    })
    res.json({
      ok: true,
      products,
    })
  }
  if (req.method === 'POST') {
    const { name, price, description } = req.body
    const { user } = req.session
    const product = await client.product.create({
      data: {
        name,
        price: +price,
        description,
        image: 'aaa',
        user: {
          connect: {
            id: user?.id,
          },
        },
      },
    })
    res.json({ ok: true, product })
  }
}
export default withApiSession(
  withHandler({
    methods: ['GET', 'POST'],
    handler,
  })
)

2. components/pagination-button

다음page 혹은 이전 page로 이동하는것을 나타내는 버튼을 component로
만들어 놓음


import { cls } from '@libs/client/utils'

interface PaginationButton {
  children: React.ReactNode ///heroIcon에서 받아올 화살표
  rOpt?: number
  direction: 'left' | 'right'  ///이전페이지 혹은 다음페이지
  page: number
  itemLength?: any  ///item갯수
  [key: string]: any
}
///home(index 페이지에서 받아올 props)

export default function PaginationButton({
  children,
  direction,
  page,
  itemLength,
  onClick,
  rest,
}: PaginationButton) {
  return (
    <button
      {...rest}
      onClick={onClick}
      className={cls(  ///prop의 조건에 따라 화살표 셋팅
        direction === 'left' || (direction === 'right' && page <= 1)  
          ? 'bottom-5'
          : 'bottom-16',
        direction === 'right' && itemLength < 5 ? 'hidden' : '',
        ///현재 한페이지에 5개 아이템이 보이게 셋팅해 놓음.
        
        direction === 'left' && page <= 1 ? 'hidden' : '',
        ///page가 1이거나 0이면 left 화살표 안보이게 함.
        
        ///그 외 공통적으로 들어가는 부분
        `fixed right-5 flex aspect-square w-14 cursor-pointer items-center justify-center rounded-full border-0 border-transparent bg-orange-400 text-white shadow-xl transition-all hover:bg-orange-500 sm:sticky sm-translate-x-[32rem]`
      )}
    >
      {children}  ///나중에 heroIcon에서 받아온 화살표 넣는 거
    </button>
  )
}

3. pages/index.tsx

다른 부분은 생략하고 pagination부분만 알아보자

import PaginationButton from '@components/pagination-button'
import useUser from '@libs/client/useUser'
import { Product } from '@prisma/client'
import type { NextPage } from 'next'
import { useRouter } from 'next/router'
import { useState } from 'react'
import useSWR from 'swr'
import FloatingButton from '../components/floating-button'
import Item from '../components/item'
import Layout from '../components/layout'

export interface ProductWithCount extends Product {
  _count: {
    favs: number
  }
}

interface ProductsResponse {
  ok: boolean
  products: ProductWithCount[]
}

const Home: NextPage = () => {
  const { user, isLoading } = useUser()
  const router = useRouter()
  const [page, setPage] = useState(1) ///page기본값은 1로
  const [limit, setLimit] = useState(5)
  ///한 page당 보여줄 item 개수는 5개로~
  
  const { data } = useSWR<ProductsResponse>(
    `/api/products?page=${page}&limit=${limit}`
  )
  ///api요청시 page와 limit를 query에 넣어서 호출함.

  const onPrevBtn = () => {
    router.push(`${router.pathname}?page=${page - 1}&limit=${limit}`)
    setPage((prev) => prev - 1)
  }
  ///이전 page 버튼을 눌렀을때, 실행되는 함수
  
  const onNextBtn = () => {
    router.push(`${router.pathname}?page=${page + 1}&limit=${limit}`)
    setPage((prev) => prev + 1)
  }
  ///다음 page버턴을 눌렀을때, 실행되는 함수.
  
  console.log(data)
  return (
    <Layout title="Home" hasTabBar>
      <div className="flex flex-col space-y-5 py-10 mb-10">
        {data?.products?.map((product) => (
          <Item
            key={product.id}
            id={product.id}
            title={product.name}
            price={product.price}
            hearts={product._count.favs}
            comments={3}
          ></Item>
        ))}
        <PaginationButton onClick={onPrevBtn} direction="left" page={page}>
        ///이전페이지 버튼눌렀을때, 보내질 props
        ///밑에 부분은 {...rest}로 받음
        
          <svg
            xmlns="http://www.w3.org/2000/svg"
            className="h-6 w-6"
            fill="none"
            viewBox="0 0 24 24"
            stroke="currentColor"
            strokeWidth="2"
          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              d="M11 15l-3-3m0 0l3-3m-3 3h8M3 12a9 9 0 1118 0 9 9 0 01-18 0z"
            />
          </svg>
        </PaginationButton>
        <PaginationButton
        ///다음Page 버튼을 눌렀을때, 실행될 버튼,
        ///itemLength가 들어가는 부분 확인할 것!!
        
          onClick={onNextBtn}
          direction="right"
          page={page}
          itemLength={data?.products.length}
        >
          <svg
            xmlns="http://www.w3.org/2000/svg"
            className="h-6 w-6"
            fill="none"
            viewBox="0 0 24 24"
            stroke="currentColor"
            strokeWidth="2"
          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              d="M13 9l3 3m0 0l-3 3m3-3H8m13 0a9 9 0 11-18 0 9 9 0 0118 0z"
            />
          </svg>
        </PaginationButton>
        <FloatingButton href="/products/upload">
          <svg
            className="h-12 w-15"
            xmlns="http://www.w3.org/2000/svg"
            fill="none"
            viewBox="0 0 24 24"
            stroke="currentColor"
            aria-hidden="true"
          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeWidth="2"
              d="M12 6v6m0 0v6m0-6h6m-6 0H6"
            />
          </svg>
        </FloatingButton>
      </div>
    </Layout>
  )
}

export default Home

NOTICE!!! pagination은 열심히 배워서 까먹지 말고 잘 알아놓자!!!!

profile
코딩하는초딩쌤

0개의 댓글