const uploadBackFile = e => {
    if (e.target.files[0]) {
      let file = e.target.files[0];
      let reader = new FileReader();

      reader.readAsDataURL(file);

      reader.onload = function (e) {
        setPreviewBackImage(e.target.result);
      };

      setter.setUploadBackImage(e.target.files[0]);
    }
  };

 

 멘토님에게 리뷰를 받고 리팩토링 과정을 거치며 코드를 한층 더 간결하게 작성할 수 있었습니다.

 

before

handleNextSlider = () => {
    const sliderElement = this.sliderRef.current;
    const itemElement = this.itemRef.current;
    const itemWidth = Math.ceil(itemElement.getBoundingClientRect().width);
    if (
      this.state.transFormPosition ===
      (sliderElement.getElementsByClassName('anotherItem').length - 4) *
        -itemWidth
    ) {
      return;
    }
 
    this.setState(
      {
        transFormPosition: this.state.transFormPosition - itemWidth,
      },
      () => {
        sliderElement.style.transform = `translate(${this.state.transFormPosition}px)`;
      }
    );
  };

 

 

after

  handleNextSlider = () => {
    const sliderElement = this.sliderRef.current;
    const { currentIndex } = this.state;
    const { subImage } = this.props;
 
    if (this.itemRef.current) {
      const itemWidth = Math.ceil(
        this.itemRef.current.getBoundingClientRect().width
      );
      if (currentIndex === subImage - 4) {
        return;
      }
 
      this.setState(
        {
          currentIndex: currentIndex + 1,
        },
        () => {
          sliderElement.style.transform = `translate(-${
            this.state.currentIndex * itemWidth
          }px)`;
        }
      );
    }
  };

 

ref를 통하여 slider의 위치를 이미지의 너비만큼 이동하도록 만든 함수입니다.

이미지의 너비는 getBoundingClientRect() 메소드를 사용하여 측정하였습니다.

화면상에서 보이는 이미지는 4개이므로 현재 index의 위치와 이미지 배열의 길이 -4가 같으면 더 이상

slider의 위치를 옮기지 않도록 하였습니다.

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

[Project-1] watCU - 별점,별점그래프  (0) 2021.09.12
[Wecode] 1차 Project : watCU 후기  (0) 2021.07.18

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

매우 즐거웠습니다. 

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

문제 상황

Add Dress 페이지의 form 태그를 통해 유저는 드레스에 대한 제반 사항을 입력하게 되고 이를 FormData에 append할 때 발생하였다.

과정을 조금 더 자세히 보면, 드레스의 각 정보들은 컴포넌트의 state에 관리되고 입력이 끝나면 submit 이벤트가 발생할 때 FormData에 각 정보들이 append 되어 서버에 보내진다.

나는 서버에 보내기 전에 FormData에 각 정보들이 잘 append되었나 확인하기 위해 console.log를 이용하여 확인하였지만 아래와 같은 이상한 객체만 반환하고 있었다.

 

let formData = new FormData();
formData.append('foo', 'test');
console.log(formData);
// FormData {}

 

 

FormData 객체란?

 

The FormData object lets you compile a set of key/value pairs to send using XMLHttpRequest. It is primarily intended for use in sending form data, but can be used independently from forms in order to transmit keyed data. The transmitted data is in the same format that the form's submit() method would use to send the data if the form's encoding type were set to multipart/form-data.

FormData 객체에 대한 설명은 MDN에 위와 같이 안내되어 있다. 단순한 객체가 아닌 XMLHttpRequest 전송을 위해 설계된 특수한 객체 형태라고 볼 수 있다.

따라서 문자열화할 수 없는 객체이기 때문에 console.log를 사용해서 프린트할 수 없다.

만약 전송 전에 FormData의 값을 확인하고 싶다면, 아래와 같이 FormData의 메소드를 사용해야 한다.

 

// FormData의 key 확인
for (let key of formData.keys()) {
  console.log(key);
}

// FormData의 value 확인
for (let value of formData.values()) {
  console.log(value);
}

 

 

참고자료:https://velog.io/@josworks27/formData-console.log

'JScript > Today I learned' 카테고리의 다른 글

[JS] While문과 for문  (0) 2021.12.10
함수형 프로그래밍이란?  (0) 2021.12.05
TIL#11 Array.reduce()함수  (0) 2021.07.11
TIL#10 Scope !중요  (0) 2021.06.14
TIL#09 UI vs API  (0) 2021.05.09

+ Recent posts