별점 기능과 별점그래프를 실시간으로 연동시키는 것은 그 과정은 어려웠지만 하나하나 원하는 대로 코드가 구현될 때 마다

매우 즐거웠습니다. 

난생 처음으로 백엔드에게 데이터를 받고 또 post를 이용하여 보내고 그 과정이 그래프라는걸 통해서 유의미한 결과물이 나오는 것은 

 

'아, 내가 정말로 백엔드와 통신을 하는중이구나!' 

 

라는 감상이 들게 만들게 만들었습니다.

제가 실시간 연동을 한 방법은 다음과 같았습니다.

 

<Detail.js(부모컴포넌트)>

export default class Detail extends Component {
constructor() {
super();
this.state = {
userInfo: [],
};
}
callStarGraphApi = () => {
fetch(
`${BASE_URL}/ratings/products/${this.props.match.params.productId}/graph`
)
.then(res => res.json())
.then(data =>
this.setState({
userInfo: data.results,
})
);
};
componentDidMount = () => {
this.callStarGraphApi();
};
render(){
return{
<StarRating callStarGraphApi={this.callStarGraphApi}>
<StarGraph userInfo={this.state.userInfo} />
}
}

 

처음 rating에 대한 정보를 컴디마를 통하여 userInfo state에 저장합니다.

그 다음 자식컴포넌트들인

StarRating에 Api호출 함수 callStarGraphApi를 props로 주고

StarGraph에 userInfo를 props로 줍니다.

 

 

<StarRating.js>

export default class StarRating extends Component {
constructor() {
super();
this.state = {
rateValue: [false, false, false, false, false]
};
}
handleStarClick = clickedIndex => {
const prevRateValue = [...this.state.rateValue];
const isClickedStarActive = prevRateValue[clickedIndex];
const isNextStarActive = prevRateValue[clickedIndex + 1];
if (isClickedStarActive && isNextStarActive) {
prevRateValue.fill(false, clickedIndex + 1);
} else if (isClickedStarActive) {
prevRateValue.fill(false, 0, clickedIndex + 1);
} else if (!isClickedStarActive) {
prevRateValue.fill(true, 0, clickedIndex + 1);
}
const rating = prevRateValue.filter(value => value).length;
fetch(`${BASE_URL}/ratings/products/${this.props.id}`, {
method: 'POST',
body: JSON.stringify({
rating: rating,
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
Authorization: localStorage.getItem('token'),
},
}).then(() => {
const { callStarGraphApi} =this.props;
callStarGraphApi();
});
this.setState({
isHover: false,
hoverRateValue: [false, false, false, false, false],
rateValue: prevRateValue,
});
};

별점을 클릭시 (여기서는 3점을 줬다고 하겠습니다.)

[true, true, true ,false ,false]가 나오게 됩니다.

그리고 true 갯수인 3을 fetch함수에서 post로 데이터를 보내게 됩니다.

 

 

이렇게 되면 기존 데이터서버에는 3점이라는 데이터가 하나 더 쌓이게 됩니다.

하지만 아쉽게도 우리는 쌓이기 전의 데이터를 받아 온 상태입니다.

최신상태의 데이터가 아니라는 것입니다.

그러니 다시 이 데이터를 호출해 줄 필요가 있습니다.

 

아까 Detail.js에서 받아온 Api호출 함수 callStarGraphApi를 호출해줍니다.

.then(() => {
const { callStarGraphApi} =this.props;

이제 데이터가 최신상태로 업데이트 됩니다.

이렇게 되면 Detail.js의 this.state.userInfo역시 최신상태로 업데이트 됩니다.

 

 

<StarGraph.js>

export default class StarGraph extends Component {
render() {
const ratingValue = this.props.userInfo.map(user => user.rating);
const totalPerson = ratingValue.filter(ratingPerson => ratingPerson).length;
const percentageList = ratingValue
.reduce(
(preValue, ratingPerson) => {
if (ratingPerson === 0) {
return preValue;
}
preValue[ratingPerson - 1] += 1;
return preValue;
},
[0, 0, 0, 0, 0]
)
.map(ratingPerson => Math.round((ratingPerson / totalPerson) * 100));
const maxPercentage = Math.max(...percentageList);
return (
<>
<div className="graphLayout">
<div className="graphContainer">
{percentageList.map((percent, index) => {
return (
<div
className={
percent >= maxPercentage
? 'maxRatingPerson'
: 'ratingPerson'
}
key={index}
style={
percent > 0 ? { height: `${percent}%` } : { height: '1%' }
}
></div>
);
})}
</div>
<ul className="scoreNumber">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</div>
</>
);
}
}

StarGraph는 reduce함수를 이용하여 각 별점의 평가자 수를 반영하도록 하였습니다.

그 다음 각 별점의 평가자 수를 전체 평가자의 수로 나눈 후 곱하기 100을 하여 백분율로 나타낸 겁니다.

 

이제 예제를 통해 설명해보겠습니다.

 

별점 1점: 2명 → 약22%

별점 2점: 1명 → 약11%

별점 3점: 2명 → 약22%

별점 4점: 2명 → 약22%

별점 5점 : 2명 → 약22%

 

총 9명이 다음과 같이 평가하였습니다.

이때 유저A가 평점을 3점을 새로이 추가했다고 합시다.

그러면 실시간 업데이트된 데이터가 StarGraph로 내려옵니다.

그렇다면...

 

별점 1점: 2명 → 20%

별점 2점: 1명 → 10%

별점 3점: 3명 → 30%

별점 4점: 2명 → 20%

별점 5점 : 2명 → 20%

 

이렇게 그래프가 변합니다.

이제 이렇게 변하는 그래프에 반응하도록 CSS로 애니메이션까지 주면 완성입니다.

'Wecode > Project' 카테고리의 다른 글

[Project-1] watCU - 슬라이더  (0) 2021.09.12
[Wecode] 1차 Project : watCU 후기  (0) 2021.07.18

+ Recent posts