위코드 2차 프로젝트로 왓챠피디아의 상세페이지를 담당하였다.
이번 프로젝트를 하면서 내가 새롭게 구현한 기능이 4가지가 있다.
여기서 별점 기능을 먼저 적어보겠다.
import { FaStar } from 'react-icons/fa';
별 이미지는 react icon
에 있는 <FaStar />
을 사용
const [clicked, setClicked] = useState([false, false, false, false, false]);
Boolean
값을 사용하여 [false,false,false,false,false]
가 기본값이 된다.svg
) 1개를 누르면 [true,false,false,false,false]
[true,false,false,false,false]
가 되는<Stars> {ARRAY.map((el, idx) => { return ( <FaStar key={idx} size="50" onClick={() => handleStarClick(el)} className={clicked[el] && 'yellowStar'} /> ); })} </Stars>
ARRAY=[0,1,2,3,4]
를 선언하여 map을 돌린다.<FaStar />
svg
5개가 map함수에 의해 돌아가고 클릭한 별의 인덱스 값이 el
에 찍히게 된다.el = 3
const handleStarClick = index => { let clickStates = [...clicked]; for (let i = 0; i < 5; i++) { clickStates[i] = i <= index ? true : false; } setClicked(clickStates); };
handleStarClick
함수의 인자는 위에서 클릭한 el
값을 index
로 받게 된다. el = index = 3
i <= 3
이 될때까지는 true
값을 반환하게 된다.[true,true,true,false,false]
이 추출되는 것이다.useEffect(() => { sendReview(); }, [clicked]); //컨디마 컨디업 const sendReview = () => { let score = clicked.filter(Boolean).length; };
filter(Boolean)
을 통해 true값만 반환해줄 수 있다.length
까지 붙여서 결국 "true=별을 클릭한 갯수"을 구현하는 것이다.scss대신 함수형 컴포넌트
const Stars = styled.div` display: flex; padding-top: 5px; & svg { color: gray; cursor: pointer; } :hover svg { color: #fcc419; } & svg:hover ~ svg { color: gray; } .yellowStar { color: #fcc419; } `;
react-icon
에서 사용한 <FaStar />
를 svg
아이콘으로 표현다는 것을 이번 기회에 알게 되었다. :hover svg { color: #fcc419; }
: 3번째 별을 hover해도 일단은 5개 모두 노란색일 것이다.& svg:hover ~ svg { color: gray; }
: hover된 별 이외에 나머지 별들(hover ~ svg
)은 회색을 줌으로써 내가 원하는 별갯수 만큼 노란색을 들어올 수 있게 하였다!!className={clicked[el] && 'yellowStar'}
을 통해 클릭한 별만큼 노란색으로 남아있도록 사용한 class값이 .yellowStar { color: #fcc419; }
이다.> 함수형 컴포넌트
import React, { useState, useEffect } from 'react'; import { FaStar } from 'react-icons/fa'; import styled from 'styled-components'; const ARRAY = [0, 1, 2, 3, 4]; function Rating() { const [clicked, setClicked] = useState([false, false, false, false, false]); const handleStarClick = index => { let clickStates = [...clicked]; for (let i = 0; i < 5; i++) { clickStates[i] = i <= index ? true : false; } setClicked(clickStates); }; useEffect(() => { sendReview(); }, [clicked]); //컨디마 컨디업 const sendReview = () => { let score = clicked.filter(Boolean).length; // fetch('http://52.78.63.175:8000/movie', { // method: 'POST', // Headers: { // Authroization: 'e7f59ef4b4900fe5aa839fcbe7c5ceb7', // }, // body: JSON.stringify({ // movie_id:1 // star: score, // }), // }); }; return ( <Wrap> <RatingText>평가하기</RatingText> <Stars> {ARRAY.map((el, idx) => { return ( <FaStar key={idx} size="50" onClick={() => handleStarClick(el)} className={clicked[el] && 'yellowStar'} /> ); })} </Stars> </Wrap> ); } export default Rating; const Wrap = styled.div` display: flex; flex-direction: column; padding-top: 15px; `; const RatingText = styled.div` color: #787878; font-size: 12px; font-weight: 400; `; const Stars = styled.div` display: flex; padding-top: 5px; & svg { color: gray; cursor: pointer; } :hover svg { color: #fcc419; } & svg:hover ~ svg { color: gray; } .yellowStar { color: #fcc419; } `;
감사합니다 많은 도움이 됐습니다!