React 별점 기능 구현

miin·2021년 10월 22일
4

내용

  • 마우스 오버로 해당 오버 별 순번까지 드래그
  • 해당 별 평점 텍스트 나타내기
  • 해당 별 클릭시 색깔 유지
  • 클릭한 해당 별 인덱스 저장 후 백엔드로 데이터 보냄

결과

코드

import React, { useState } from 'react';
import styled from 'styled-components';

const Score = () => {
  const [hovered, setHovered] = useState(null);
  const [clicked, setClicked] = useState(null);
  
  const goToFetch = e => {
    setClicked(e.target.id);
    fetch(`http://10.58.3.24:8000/products/1`, {
      //사용할 http 메소드 
      method: 'POST',
      //토큰
      headers: {
        Authorization: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxfQ.loTjeBWZ9SeXV-BcIxqOtX37AN30ROvsZl0_udeeRJU',
      },
      //서버에 보낼 데이터 (별점)
      body: JSON.stringify({
        rating: e.target.id,
      }),
    });
  };

  return (
    <ReviewBox>
      <ReviewTextBox>
        <p>이 책을 평가해주세요!</p>
        {[1, 2, 3, 4, 5].map(num => (
          <HiddenText key={num} show={hovered === num}>
            {textList[num - 1]}
          </HiddenText>
        ))}
      </ReviewTextBox>
      <StarContainer>
        {[1, 2, 3, 4, 5].map(el => (
          <i
            className={`fas fa-star ${
              (clicked >= el) | (hovered >= el) && 'yellowStar'
            }`}
            key={el}
            onMouseEnter={() => setHovered(el)}
            onMouseLeave={() => setHovered(null)}
            onClick={() => setClicked(el)}
          />
        ))}
      </StarContainer>
    </ReviewBox>
  );
};

export default Score;

//style-component 사용
const textList = [
  '별로에요',
  '그저 그래요',
  '보통이에요',
  '좋아요',
  '최고예요',
];

const ReviewBox = styled.div`
  padding: 30px;
  color: #999;
  font-size: 20px;

  i {
    margin: 20px 10px 20px 0;
    opacity: 0.1;
    cursor: pointer;
    font-size: 50px;
  }

  .yellowStar {
    color: orange;
    opacity: 1;
  }
`;

const ReviewTextBox = styled.div`
  position: relative;
  text-align: center;
  padding-bottom: 50px;
`;

const StarContainer = styled.div`
  text-align: center;
  border: none;
  background-color: white;
`;

const HiddenText = styled.p`
  position: absolute;
  top: 50px;
  left: 50%;
  width: 130px;
  height: 30px;
  padding-top: 7px;
  transform: translate(-50%, -50%);
  color: white;
  background-color: #1f8ce6;
  border-radius: 4px;
  font-size: 16px;

  ${({ show }) => (show ? `display:block` : `display: none`)}
`;

마우스 오버시 해당 별 순번까지 드래그, 해당 별 클릭시 색깔 유지

  const [hovered, setHovered] = useState(null);
  const [clicked, setClicked] = useState(null);

<StarContainer>
  //별 아이콘 다섯개 만들기      
  {[1, 2, 3, 4, 5].map(el => (
          <i
         //className에 조건문 넣기
            className={`fas fa-star ${
   //el만큼 클릭 하거나 || el만큼 호버를 하면 yellowStar 클래스를 실행 
              (clicked >= el) | (hovered >= el) && 'yellowStar'
            }`}
            key={el}//1,2,3,4,5
			id={el}
            onMouseEnter={() => setHovered(el)}
            onMouseLeave={() => setHovered(null)}
            onClick={goToFetch}
          />
        ))}
      </StarContainer>

const ReviewBox = styled.div`
  padding: 30px;
  color: #999;
  font-size: 20px;

  i {
    margin: 20px 10px 20px 0;
    opacity: 0.1;
    cursor: pointer;
    font-size: 50px;
  }

  .yellowStar {
    color: orange;
    opacity: 1;
  }
`;

해당 별 평점 텍스트 나타내기

const textList = [
  '별로에요',
  '그저 그래요',
  '보통이에요',
  '좋아요',
  '최고예요',
];

  const [hovered, setHovered] = useState(null);

      <ReviewTextBox>
        <p>이 책을 평가해주세요!</p>
        {[1, 2, 3, 4, 5].map(num => (
          //show={호버한 인덱스와 텍스트 인덱스가 같으면 화면에 나타내기}
          <HiddenText key={num} show={hovered === num}>
          //맵 인덱스와 textList인덱스 차이가 나서 -1을 해준다
            {textList[num - 1]}
          </HiddenText>
        ))}
      </ReviewTextBox>
      <StarContainer>
        
const HiddenText = styled.p`
  position: absolute;
  top: 50px;
  left: 50%;
  width: 130px;
  height: 30px;
  padding-top: 7px;
  transform: translate(-50%, -50%);
  color: white;
  background-color: #1f8ce6;
  border-radius: 4px;
  font-size: 16px;

  ${({ show }) => (show ? `display:block` : `display: none`)}
`;

클릭한 해당 별 인덱스 저장 후 백엔드로 데이터 보냄

<StarContainer>
        {[1, 2, 3, 4, 5].map(el => (
          <i
            className={`fas fa-star ${
              (clicked >= el) | (hovered >= el) && 'yellowStar'
            }`}
            key={el}
            id={el}
            onMouseEnter={() => setHovered(el)}
            onMouseLeave={() => setHovered(null)}
	//onClick시 goToFetch함수를 호출함
            onClick={goToFetch}
          />
        ))}
      </StarContainer>

//event를 인자로 받아옴
const goToFetch = e => {
//콘솔로 e.target.id가 잘 들어오는지 확인
    console.log('eti', e.target.id);
//setClicked를 e.target.id로 변경 1,2,3,4...
    setClicked(e.target.id);
//fetch 함수를 통해 백엔드로 보내줌
    fetch(`http://10.58.3.24:8000/products/1`, {
    method: 'POST',
      //토큰
    headers: {
    Authorization: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxfQ.loTjeBWZ9SeXV-BcIxqOtX37AN30ROvsZl0_udeeRJU',
      },
    body: JSON.stringify({
//rating-> 백엔드와 변수명 같은걸로
    rating: e.target.id,
    console.log('clicked->', { clicked });
      }),
    });
  };

0개의 댓글