메인-프로젝트/Next.js - 오늘 뭐먹지? 프로젝트

7. 모든 음식들을, 카테고리 별로, 태그 별로 검색되도록 구현하자

이게뭐당가 2022. 12. 2. 23:53

핵심 기능중 하나인 음식 페이지를 꾸며볼 차례입니다.

 

 음식들을

카테고리별 (한식,양식,중식 ... ),

태그별로(매움, 짭짤, 달달 ...)

로 구분지어 볼 수 있어야 했습니다.

 

주요한 기능이기에, "느린 UX 보다는, 빠른 UX 가 필요했습니다."

로딩은 조금 있을지언정, 좋은 유저경험을 위해 getStaticProps 로 "사전 데이터 페칭을 진행했습니다"

 

 

 

1. AllFoodsPage 에, 사전 데이터 페칭을 해줍니다.

페칭된 데이터들을 음식들이 있는 컴포넌트로, 넘겨줍니다.

 

import FoodCategoryHeader from "../../components/food-components/food-category-header";
import { connectDb, findAllFoods } from "../../helper/db-util";
import Head from "next/head";

function AllFoodsPage(props) {
  const { allfoods } = props;

  return (
    <div>
      <Head>
        <title> All Foods with Category</title>
        <meta name="description" content="this show all foods with category" />
      </Head>
      {<FoodCategoryHeader foodData={allfoods} />}
    </div>
  );
}

export async function getStaticProps() {
  const client = await connectDb();
  const allFoods = await findAllFoods(client);

  const arrangeAllFoods = allFoods.sort((A, B) => (A.name > B.name ? 1 : -1));

  return {
    // 직렬화 문제로 인해, 두번 변환해서 사용
    props: { allfoods: JSON.parse(JSON.stringify(arrangeAllFoods)) },
  };
}
export default AllFoodsPage;

 

* Array.sort() 를 통해, 이름순으로, 정리하여 넣어줍니다.

 

 

 

2. Food를 보여줄 컴포넌트를 만들어, FoodData 를 받고, filter 를 통해,

버튼을 누르면, 필요한 데이터만 보이게 만들어줍니다.

 

import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/css";

import FoodList from "./food-list";
import styles from "./food-category-header.module.css";
import { useState, useEffect } from "react";

// 카테고리 누르면, Allfoods-page 에서 온 Data 들을, filter  처리 해서, Food-list-component 로 보내줌
// All 을 누르면,   Allfoods-page 에서 온 Data들을,   filter 처리 없이, Food-list-component 로 보내줌

function FoodCategoryHeader(props) {
  const { foodData } = props;
  const [insertFoodData, setInsertFoodData] = useState(foodData);

  // 버튼 누르면, food 선별작업 해서, 새로운 데이터를 만든 후, Foodlist 로 넘겨준다.

  function foodFilter(category) {
    const filteredFoods = foodData.filter((food) => food.category === category);

    setInsertFoodData(filteredFoods);
  }

  function fansyFilter() {
    const filteredFoods = foodData.filter((food) => food.fansy == "true");

    setInsertFoodData(filteredFoods);
  }

  return (
    <div className={styles.maindiv}>
      <header className={styles.header}>
        <Swiper spaceBetween={23} slidesPerView={6}>
          <SwiperSlide>
            <li onClick={() => setInsertFoodData(foodData)}>전체</li>
          </SwiperSlide>
          <SwiperSlide>
            <li onClick={() => foodFilter("다이어트")}>식이</li>
          </SwiperSlide>
 
                                      ....
 
          <SwiperSlide>
            <li onClick={() => foodFilter("디저트")}> 디저트 </li>
          </SwiperSlide>
          <SwiperSlide>
            <li onClick={() => fansyFilter()}> 고급 </li>
          </SwiperSlide>
          <SwiperSlide>
            <li> </li>
          </SwiperSlide>
        </Swiper>
        <p>&#5130; 스와이프하세요 &#5125; </p>
      </header>
      <main>
        <FoodList foodData={insertFoodData} />
      </main>
    </div>
  );
}
export default FoodCategoryHeader;

카테고리를 누르면, foodFilter 함수가 호출되어, 콜백형태로 실행되게 만들어줍니다.

 

React 는 onClick={함수이름} 으로, 인수 없이 함수를 호출해야, 평가된 함수가,

이벤트 리스너에 반응해 실행을 하게 됩니다.

 

onClick={foodFilter("다이어트")} 처럼 쓰게 되면, 이는 "함수가 바로 실행" 되므로, 콜백 형태로 적어준 것입니다.

 

이렇게 하면!

 

 

이렇게 적용된다!

3. 태그별에는 filter 의 조건에, includes() 를 사용하여

여러가지 태그중 하나만 들어 있어도 필터링이 되게만듭니다.

 

function FoodTagsHeader(props) {
  const { foodData } = props;

  const sortedFoodData = foodData.sort((A, B) => (A.name > B.name ? 1 : -1));
  const [insertFoodData, setInsertFoodData] = useState(foodData);

  // 버튼 누르면, food 선별작업 해서, 새로운 데이터를 만든 후, Foodlist 로 넘겨준다.
  // 태그가 하나라도 포함되어있으면, 보여준다.

  function foodFilter(taste) {
    const filteredFoods = foodData.filter((food) => food.taste.includes(taste));

    setInsertFoodData(filteredFoods);
  }

끄읏