별점 기능과 별점그래프를 실시간으로 연동시키는 것은 그 과정은 어려웠지만 하나하나 원하는 대로 코드가 구현될 때 마다
매우 즐거웠습니다.
난생 처음으로 백엔드에게 데이터를 받고 또 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 |