restaurants.tsx

김종민·2022년 9월 22일
0

Nuber-Client

목록 보기
8/21

들어가기
Client로 접속했을때,
모든 식당들이 나열되어 보이는 page


1. src/pages/client/restaurants.tsx

import { gql, useQuery } from '@apollo/client'
import React, { useState } from 'react'
import { useForm } from 'react-hook-form'
import { Link } from 'react-router-dom'
import { useNavigate } from 'react-router-dom'
import Restaurant from '../../components/restaurant'
import { CATEGORY_FRAGMENT, RESTAURANT_FRAGMENT } from '../../fragments'
import {
  RestaurantsPageQuery,
  RestaurantsPageQueryVariables,
} from '../../graphql/__generated__'

const RESTAURANTS_QUERY = gql`
  query restaurantsPage($input: RestaurantsInput!) {
    allCategories {
      ok
      error
      categories {
        ...CategoryParts
      }
    }

	///restaurantsPage를 실행시키면,
    ///server의 allCategories와 restaurants query가 실행됨.
    ///restaurants의 input(RestaurantInput)부분은 
    ///page를 입력받는 부분임.
    ///...CategoryParts와 ...RestaurantParts 부분은
    ///frahment로 만들어 놓은 부분.
    ///다음 post에서  다룰 예정.
    
    restaurants(input: $input) {
      ok
      error
      totalPages
      totalResults
      results {
        ...RestaurantParts
      }
    }
  }
  ${RESTAURANT_FRAGMENT}
  ${CATEGORY_FRAGMENT}
`

interface IFromProps {
  search: string
}
///restaurant search하기 위해서 만들어 놓은 props

const Restaurants = () => {
  const [page, setPage] = useState(1)
  ///page의 default값은 1로~
  
  const { data, loading } = useQuery<
    RestaurantsPageQuery,
    RestaurantsPageQueryVariables
  >(RESTAURANTS_QUERY, {
    variables: { input: { page } },
  })
  ///위에서 만든 restaurantsPage Query임.
  ///variables는 page를 input함.

  const onNextPageClick = () => setPage((current) => current + 1)
  const onPrevPageClick = () => setPage((current) => current - 1)
	///page를 넘기는 화살표를 클릭했을시 실행 될 함수.

  const { register, handleSubmit, getValues } = useForm()
  ///useForm
  
  const navigate = useNavigate()
  ///useNavigate설정.
  
  const onSearchSubmit = () => {
    console.log(getValues())
    const search = getValues().search
    navigate({
      pathname: '/search',
      search: `?term=${search}`,
    })
  }
  ///serch칸에서 keyword를 입력후 enter했을때,
  ///실행될 함수.
  ///밑의 form(search)에서 state를 받아서
  ///    http://localhost:3000/search?term=ccc
  ///의 주소로 이동시켜줌.
  ///term이 keyword임.
  
  return (
    <div>
      <form
        onSubmit={handleSubmit(onSearchSubmit)}
        className="bg-gray-800 w-full py-40 flex items-center justify-center"
      >
      ///search Restaurant react-hook-form
        <input
          {...register('search', { required: true, min: 3 })}
          type="search"
          className="input rounded-md border-0 w-3/4 md:w-7/12"
          placeholder="Search Restaurant"
        />
      </form>
      ///Search restaurant react-hook-form
      
      {!loading && (
        <div className="px-5 mt-8 pb-20 max-w-screen-2xl mx-auto">
          <div className="flex justify-around max-w-sm mx-auto">
          ///allCategories로 불러들이 data 나열함
                  {data?.allCategories.categories?.map((category) => (
              <Link key={category.id} to={`category/${category.slug}`}>
  ///category 이미지 클릭시 그 category 페이지로 이동.      
                <div>
                  <div
                    className="w-16 h-16 bg-cover group-hover:bg-gray-200 rounded-full"
                    style={{ backgroundImage: `url(${category.coverImg})` }}
                  ></div>
                  <span className="mt-1 text-sm text-center font-bold">
                    {category.name}
                  </span>
                </div>
              </Link>
            ))}
          </div>
          <div className="mt-16 grid md:grid-cols-3 gap-x-5 gap-y-10">
           
///restaurants를 화면에 뿌려줌.
{data?.restaurants.results?.map((restaurant) => (
///<Restaurant> component를 만들어 놓앗음.
              <Restaurant
                key={restaurant.id}
                id={restaurant.id + ''}
                coverImg={restaurant.coverImg}
                name={restaurant.name}
                categoryName={restaurant.category?.name}
              />
            ))}
          </div>
          <div className="grid grid-col-3 text-center max-w-md items-center mx-auto mt-10">
          
          ///Pagination을 설정함.
            {page > 1 ? (
              <button
                onClick={onPrevPageClick}
                className="focus:outline-none font-medium text-2xl"
              >
                &larr;
              </button>
            ) : (
              <div></div>
            )}
            <span>
              Page {page} of {data?.restaurants.totalPages}
            </span>
            {page !== data?.restaurants.totalPages ? (
              <button
                onClick={onNextPageClick}
                className="focus:outline-none font-medium text-2xl"
              >
                &rarr;
              </button>
            ) : (
              <div></div>
            )}
          </div>
        </div>
      )}
    </div>
  )
}

export default Restaurants

하나의 Query에 server의 두개의 query(allCategories, restaurants)를 호출한다는 점을 유심히 알아둔다.

2. src/components/restaurant.tsx

하나의 restaurant component는 너무많이 사용되어서
component로 만듬

import React from 'react'
import { Link } from 'react-router-dom'

interface IRestaurantProps {
  id: string
  coverImg: string
  name: string
  categoryName?: string
}
///id, coverImg, name, categoryName을 받음.

const Restaurant: React.FC<IRestaurantProps> = ({
///component의 type은 React.Fc임.
  id,
  coverImg,
  name,
  categoryName,
}) => {
  return (
    <Link to={`/restaurants/${id}`}>
    ///클릭하면, restaurant detail page로 이동함.
      <div className="flex flex-col">
        <div
          style={{ backgroundImage: `url(${coverImg})` }}
          className="py-28 bg-center bg-cover mb-2"
        ></div>
        <h3 className="text-xl font-medium">{name}</h3>
        <span>{categoryName}</span>
      </div>
    </Link>
  )
}

export default Restaurant

NOTICE!!
client user가 접속했을때, 맨 처음에 나오는 page.
front에서 하나의 query(restaurantsPage)로 server의 두개의
query(allCategories, restaurants)를 실행시켜서 두개의 data를 불러옴,

profile
코딩하는초딩쌤

0개의 댓글