이전에 작성한 코드를 이어서 별점 컴포넌트에 마우스 호버 효과를 추가했다.
export default function StarRating({ maxRating = 5 }) {
const [rating, setRating] = useState(0);
const [tempRating, setTempRating] = useState(0);
return (
<div style={containerStyle}>
<div style={starContainerStyle}>
{Array.from({ length: maxRating }, (_, i) => (
<Star
key={i}
onRate={() => setRating(i + 1)}
full={tempRating ? tempRating >= i + 1 : rating >= i + 1}
onHoverIn={() => setTempRating(i + 1)}
onHoverOut={() => setTempRating(0)}
/>
))}
</div>
<p style={textStyle}>{tempRating || rating || ""}</p>
</div>
);
}
마우스가 호버될 때의 별점 값을 저장하기 위해 temRating이라는 state를 추가했다. 초기값은 0으로 설정했다.
const [tempRating, setTempRating] = useState(0);
이렇게 하면 별 위에서 마우스를 움직일 때마다 호버되는 별의 수를 저장하고 다룰 수 있다.
Star 컴포넌트에 마우스 호버에 대한 이벤트를 추가 하기 위해 StarRating 컴포넌트에 이렇게 작성해 prop으로 보내준다.
onHoverIn={() => setTempRating(i + 1)}
onHoverOut={() => setTempRating(0)}
Star 컴포넌트에 전달된 onHoverIn과 onHoverOut 함수를 사용하여, 각각의 star에 onMouseEnter와 onMouseLeave 이벤트를 연결해준다. 이렇게 하면 별 위에 마우스가 올라가면 onHoverIn 함수가 호출되고, 별에서 내려오면 onHoverOut 함수가 호출된다.
function Star({ onRate, full, onHoverIn, onHoverOut }) {
return (
<span role="button" style={starStyle} onClick={onRate} onMouseEnter={onHoverIn}
onMouseLeave={onHoverOut}>
{full ? (
꽉찬 별 아이콘 코드
) : (
비어있는 별 아이콘 코드
)}
</span>
);
}
그리고 StarRating컴포넌트에서 full prop의 조건도 수정하여, 호버 상태에서는 tempRating 값을 사용하고 그렇지 않으면 기존 rating값을 사용하게 해준다.
full={tempRating ? tempRating >= i + 1 : rating >= i + 1}
마지막으로, 텍스트 출력 부분도 수정하여 tempRating 값이 존재하면 그것을 보여주고, 그렇지 않은 경우에는 rating 값을 보여준다. 만약 둘 다 값이 없다면 빈 문자열을 출력한다.
<p style={textStyle}>{tempRating || rating || ""}</p>
이렇게 해서 별 위에 마우스 움직여서 호버하면 호버된 별 수만큼 별점이 바뀌고 별 위에 마우스가 없으면 기존 별점으로 돌아가게 된다! 결과는 아래와 같다.
참고로 별이 클릭되어 full 상태에서 숫자에 멈추는 기능은 예전에 썼던 setRating(i + 1)
코드로 구현 된 거다. 순간 이 기능은 어떻게 한거였지? 하고 의문이 들어서 다시 코드를 살펴봐야 했다.
사용자가 StarRating의 색깔과 사이즈 등등을 조절할 수 있게 resuable하게 만들었다. 이렇게 하면 사용자가 색상, 사이즈, 메시지, 기본 별점 등 여러 요소를 조절하여 컴포넌트를 사용할 수 있다.
별에 마우스가 호버되는 숫자에 따라 서로 다른 메시지를 보여주고 싶다면, messages prop을 사용하여 메시지 배열을 전달할 수 있다.
<StarRating
maxRating={5}
messages={["Terrible", "Bad", "Okay", "Good", "Amazing"]}
/>
사용자가 별의 사이즈를 조정하고 색상을 변경할 수 있다.
<StarRating size={24} color="red" defaultRating={3} />
별점 컴포넌트가 처음 렌더링될 때 기본 별점을 지정하고 싶다면, defaultRating prop을 사용한다.
<StarRating defaultRating={3} />
Test 컴포넌트를 생성하고 별점 정보를 추적하기 위해 새로운 state인 movieRating 을 만들었다. 사용자가 별을 클릭하면 해당 별의 개수만큼 movieRating이 업데이트되어야 한다. 그래서 StarRating 컴포넌트에서 필요한 정보를 얻기 위해 prop을 전달한다.
import { useState } from "react";
import StarRating from "./StarRating";
export default function Test() {
const [movieRating, setMovieRating] = useState(0);
return (
<div>
<StarRating color="blue" maxRating={10} onSetRating={setMovieRating} />
<p>This movie was rated {movieRating} stars</p>
</div>
);
}
StarRating 컴포넌트의 경우, 별을 클릭할 때 아래 코드가 실행된다.
<Star
key={i}
onRate={() => {
setRating(i + 1);
onSetRating(i + 1);
}}
여기서, 별이 클릭되면 setRating을 사용해 별점 컴포넌트의 상태를 업데이트하고, 동시에 부모 컴포넌트인 Test 컴포넌트의 setMovieRating 함수로 선택된 별점 값을 전달한다. 이렇게 Test 컴포넌트는 별이 몇개 눌러졌는지 알게 되는 것이다. 결과적으로 사용자가 별을 클릭하면 해당 별의 개수에 따라 movieRating이 업데이트되어 출력된다.