Project | React - Webucks Clone Coding [Mission 6]

Wook·2021년 12월 6일
0

[Mission 6] 커피 리스트 페이지 커피별 좋아요 기능 구현하기


- 리스트 페이지에서 특정 커피의 하트 버튼을 눌렀을 때 그 커피의 하트만 붉게 변해야 합니다. 다시 누르면 하트가 원래대로 돌아옵니다.


⭐️ My Thoughts

ComponentMap을 활용한다면 쉽게 구현할 수 있는 단계이다. 사실 그 활용 단계는 이전 단계인 5단계에서 모두 진행했고, 그 단계보다 훨씬 구현이 쉬운단계이기에, 그리고 리스트 페이지는 이미 Map을 통해 구현이 완료되있기 때문에 Component에 하트 아이콘에 관한 기능만 추가해주면 된다.


📲 구현 코드

=> coffeecard.js : 이전에 구현했던 커피카드의 Component


import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faHeart as regularHeart } from "@fortawesome/free-regular-svg-icons";
import { faHeart as solidHeart } from "@fortawesome/free-solid-svg-icons";
import { Link } from 'react-router-dom';
import { useState, } from 'react';

function CoffeeCard(props) {

    const [heartshape, heartshapeChange] = useState(regularHeart);
    function click() {
        if (heartshape === regularHeart) {
            heartshapeChange(solidHeart);
        }
        else {
            heartshapeChange(regularHeart);
        }
    } // State와 function을 통해 하트를 호출 후, 클릭시 모양이 바뀌도록 설계

    return (
        <li><Link to="/Detail"><img src={props.item.imgsrc} alt="커피이미지" /></Link>
            <div className="nameandheart">
                <span><Link to="/Detail">{props.item.coffeename}</Link></span>
                <a href="#" className="heart3"><FontAwesomeIcon icon={heartshape} onClick={click} /></a>
              // 이번 단계에서 추가 구현한 단계로써, State를 통해 구현
            </div>
        </li>
    )
}

export default CoffeeCard;

기존 Coffee card의 Component에서 하트에 관련된 이벤트와 State를 추가 구현해줌으로써 바로 원하는 기능 적용이 가능해진다.


=> coffeelistdata.json (추가될 coffeecard의 데이터)

{
  "coffeelist1": [
    {
      "imgsrc": "/images/coffeeimg.jpeg",
      "coffeename": "아메리카노"
    },
    {
      "imgsrc": "/images/뿌링클.jpeg",
      "coffeename": "뿌링클"
    },
    {
      "imgsrc": "/images/엽떡.jpeg",
      "coffeename": "엽떡"
    },
    {
      "imgsrc": "/images/짜파게티.jpeg",
      "coffeename": "짜파게티"
    },
    {
      "imgsrc": "/images/토마토.jpeg",
      "coffeename": "토마토"
    },
    {
      "imgsrc": "/images/허니콤보.jpeg",
      "coffeename": "허니콤보"
    },
    {
      "imgsrc": "/images/coffeeimg.jpeg",
      "coffeename": "카푸치노"
    },
    {
      "imgsrc": "/images/coffeeimg.jpeg",
      "coffeename": "카페라떼"
    },
    {
      "imgsrc": "/images/짜파게티.jpeg",
      "coffeename": "짜파게티"
    },
    {
      "imgsrc": "/images/생수.jpeg",
      "coffeename": "생수"
    }
  ],
  "coffeelist2": [
    {
      "imgsrc": "/images/coffeedetailpage.png",
      "coffeename": "라떼는 말이야"
    },
    {
      "imgsrc": "/images/후라이.jpeg",
      "coffeename": "후라이"
    }
  ]
}

=> List.js (커피리스트의 전체 페이지)

import React from 'react';
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Link } from 'react-router-dom';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faHeart as regularHeart } from "@fortawesome/free-regular-svg-icons";
import { faHeart as solidHeart } from "@fortawesome/free-solid-svg-icons";
import CoffeeCard from './CoffeeCard';

import './List.scss';
import TopNav from '../TopNav';


function List() {
    const navigate = useNavigate();
    const goToDetail = () => {
        navigate("/Detail");
    }

    const [coffeeCard, setCoffeeCard] = useState([]);
    useEffect(() => {
        fetch('http://localhost:3000/data/coffeelistdata.json')
            .then(res => res.json())
            .then(res =>
                setCoffeeCard(res));
    }, [])

    return (
        <>
            <TopNav />
            <div className="menu-banner">
                <span className="cold">콜드 브루 커피</span>
                <img src="/images/coffeeicon.png" alt="커피" className="icon" />
                <span className="dcf">디카페인 에스프레소 샷 추가 가능(일부 음료 제외)</span>
            </div>

            <div className="menu-list">
                <div className="linetemplate">
                    <ul>
                        {coffeeCard.coffeelist1 && coffeeCard.coffeelist1.map((e, i) => {
                            return (
                                <CoffeeCard
                                    item={e}
                                />
                            )
                        })} // map을 활용해 커피카드를 연쇄적으로 나열

                    </ul>
                </div>
            </div>

            <div className="menu-banner">
                <span className="cold">브루드 커피</span>
                <img src="/images/coffeeicon.png" alt="커피" className="icon" />
                <span className="dcf">디카페인 에스프레소 샷 추가 가능(일부 음료 제외)</span>
            </div>

            <div className="menu-list">
                <div className="linetemplate">
                    <ul>

                        {coffeeCard.coffeelist2 && coffeeCard.coffeelist2.map((e, i) => {
                            return (
                                <CoffeeCard
                                    item={e}
                                />
                            ); // map을 활용해 커피카드를 연쇄적으로 나열
                        })}
                    </ul>
                </div>
            </div>
        </>
    );
}

export default List;

반복되는 coffeecard의 컴포넌트를 map을 활용하여 구현한 1단계에서 그 내부의 각각의 하트버튼에 클릭시 이벤트(하트 내부가 채워지고 비워짐)을 구현하는 단계였다. Component에 하트에 관한 이벤트를 구현하기 위한 useState와 그에 해당하는 function만 구현해준다면 List.js에서 map구현시에 알아서 제각각의 하트 기능을 구현해주기 때문에 간편하게 구현할 수 있었다.


⛳️ 구현 화면


🐳 느낀 점

ReactComponent를 활용하여 쉽게 구현할 수 있었다. 이전 단계(5단계)에서 사용한 기능만 쓸 줄 안다면 쉽게 구현할 수 있었기에 큰 문제 없이 구현할 수 있었다.
(음식의 리스트는 생각나는 음식을 사용했습니다..)

profile
지속적으로 성장하고 발전하는 진취적인 태도를 가진 개발자의 삶을 추구합니다.

0개의 댓글