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

매우 즐거웠습니다. 

난생 처음으로 백엔드에게 데이터를 받고 또 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