웹/앱에서 흔히 보이는 별점 리뷰 컴포넌트를 구현해서 스토리북에 추가해보겠습니다. 그리고 스토리북을 이용해 컴포넌트를 사용하는 방법을 보여드리겠습니다.
가장 먼저 떠오른 것은 순회하는 방법이었습니다. 별점 5점부터 1점까지 배열을 먼저 생성하고, 배열에 있는 요소를 하나씩 순회하면 1인 경우 원하는 <img> 요소를 리턴하고 그리고 아닌 경우에도 원하는 <img> 요서를 리턴하는 방식을 생각했습니다.
const fiveStarRating = [1,1,1,1,1]
const fourStarRating = [1,1,1,1,0]
const threeStarRating = [1,1,1,0,0]
const twoStarRating = [1,1,0,0,0]
const oneStarRating = [1,0,0,0,0]
const noRatings = [0,0,0,0,0]
import star from "../../assets/star-review.png";
import emptyStar from "../../assets/empty_star_icon.svg";
interface ReviewRatingProp {
reviewRating?: number[];
}
export const ReviewRating: React.FC<ReviewRatingProp> = ({ reviewRating }) => {
return (
<div className="flex items-center gap-[2px]">
{reviewRating?.map((i) =>
i === 1 ? (
<img src={star} alt="yellow star" className="size-4" />
) : (
<img src={emptyStar} alt="empty star" className="size-4" />
)
)}
</div>
);
};
공식문서를 참고해서 기본적인 셋팅이 완료된 코드입니다. 참고로 파일은 컴포넌트로 사용하기 때문에 ____.stories.ts 사용하시면 안돼고, _____.stories.tsx를 사용하셔야 됩니다.
export default {
title: "Ratings", // 스토리북 실행했을 때 나타나는 제목
component: ReviewRating, // 컴포넌트 추가
tags: ["autodocs"], // docs 생성
parameters: {
layout: "centered", // 요소를 화면 중간에 배치
},
} as Meta;
const Template: StoryFn<typeof ReviewRating> = (args) => (
<ReviewRating {...args} />
);
처음에 생각했던 배열을 인자로 컴포넌트의 props (args)로 넘겨서 배열에 요소가 1인 경우에 노란색 별 이미지를 출력하고, 0인 경우 그레이색 별을 출력하는 방식으로 진행했습니다.
이제 데이터를 호출하고 사용자의 리뷰 점수에 따라 컴포넌트를 구현하면 될 것 같네요!
const userDetail = [
{id: 1, user: 'Bob', review: 5},
{id: 1, user: 'Sally', review: 2},
{id: 1, user: 'Jelly', review: 3}
]
export const FiveStars = Template.bind({});
FiveStars.args = {
reviewRating: [1, 1, 1, 1, 1],
};
export const FourStars = Template.bind({});
FourStars.args = {
reviewRating: [1, 1, 1, 1, 0],
};
export const ThreeStars = Template.bind({});
ThreeStars.args = {
reviewRating: [1, 1, 1, 0, 0],
};
export const TwoStars = Template.bind({});
TwoStars.args = {
reviewRating: [1, 1, 0, 0, 0],
};
export const OneStar = Template.bind({});
OneStar.args = {
reviewRating: [1, 0, 0, 0, 0],
};
export const NoReviews = Template.bind({});
NoReviews.args = {
reviewRating: [0, 0, 0, 0, 0],
};
<>
{userDetail.map((data) => {
if(data.review === 5) {
return <ReviewRating {...FiveStars.args} />
} else if (data.review === 4) {
return <ReviewRating {...FourStars.args} />
} else { // 리뷰가 0인경우
return <ReviewRating {...NoReviews.args} />
}
//이런식으로 이어서 하면 됩니다!
})}
</>