1차 프로젝트 후기 - 러쉬코리아 클로닝

Alice Kim·2021년 5월 23일
6

Team Project

목록 보기
1/1

1. About Project

1) 목표

  • 현재까지 배운 기술 스택으로 러쉬코리아 웹싸이트 클론하기
  • 처음으로 Backend와 팀으로 진행되는 프로젝트인 만큼 협업의 큰 틀 이해하기
  • 동료 Frontend와 협업하기

2) 구성원

  • Frontend : 2명
  • Backend : 3명

3) 기간

  • 2021.05.10 ~2021.05.21(12일간)

2. Tech Stack

  • Frontend: React.js(Class component), JavaScript(ES6), SASS
  • Backend: Django, Python
  • 협업 Tool: Git, Trello

3. Main Result

프로젝트 종료 후, 직접 구현한 기능은 🚩, 팀원이 구현한 기능은 ➕

1) 로그인/회원가입 페이지➕

  • RegEx를 이용한 validation check
  • JWT, Local Storage 이용

2) 메인 페이지➕

  • 네비게이션 바를 호버할 때 나타나는 메뉴 리스트
  • 세 가지 종류의 이미지 슬라이드
  • 모달창을 통한 제품 검색 기능

3) 제품 리스트 페이지🚩

  • GET method Fetch를 통한 제품 전체 리스트 요청
  • 각 제품에 호버할 때 나타나는 장바구니 담기 아이콘을 통한 주문 기능
  • DB의 실시간 재고 연동을 통해 재고량보다 초과 주문 선택 시 경고창 모달 로직
  • DB의 실시간 재고 연동을 통해 품절 목록 자동 업데이트 로직
  • Better UX를 위한 Load More 기능 추가
  • 제품 상세 페이지 동적 라우팅 연결
  • createPortal로 공용 컴포넌트 모달 생성
  • 찜 기능 ➕

4) 제품 상세 페이지🚩

  • GET method Fetch를 통한 특정 제품 상세 정보 요청
  • DB의 실시간 재고 연동을 통해 재고량보다 초과 주문 선택 시 경고창 모달 로직
  • PATCH method Fetch를 통한 장구바니 담기 기능 구현
  • CreateRef(), scrollIntoView()로 하단의 상품 후기 & 페이지 상단으로 smooth한 스크롤 구현
  • 상품 후기 Pagination 구현
  • DB의 평점에 따른 ⭐ 표시 로직 구현

5) 장바구니 페이지🚩

  • 장바구니에 담긴 제품의 수량 조절 시, DB 상의 재고량보다 초과 선택 시 경고창 모달 로직 구현
  • 개별 상품 삭제 및 모든 상품 삭제 기능 추가
  • DB상 장바구니에 담긴 모든 제품의 총액 계산 기능
  • 선택 된 제품만 주문 금액이 다시 계산되도록 로직 구현

4. My Goal

1) 갓 배운 React(class component)의 여러 개념들을 익숙하게 만드는 것

위코드 부트캠프 시작 전, 개인적으로 몇 가지 토이 프로젝트들을 진행하면서 JavaScript는 익숙한 편이었다. React도 functional component의 개념까지는 이해하고 들어 왔는데, 1차는 class component로 진행된 다고 하여 완전 생무지에서 시작된 프로젝트였다.

토이 프로젝트를 하며 무언가를 직접 만들어보면 흐름과 개념이 잡힌다는 것을 깨달았었는데, 이번 팀 프로젝트를 통해 React class component를 꼭 나의 것으로 만들고 싶었다.

2) 장바구니 기능 구현하기

이번 팀 프로젝트를 통해서 Frontend 혼자서는 구현하기 어려운 장바구니 기능을 꼭 해보고 싶었다.

Backend와 어떤 식으로 통신이 되는지, 어떤 순서로 제품이 장바구니에 담기고, 수정되고, 삭제되는 지 배우고 싶었기 때문이다.

3) Load More/Pagination

실제 러쉬코리아 싸이트에는 구현되어 있지 않은 Load More 기능을 구현하고 싶었다.

프로젝트 시작 전 읽게된 아티클에서 Infinite scroll, Load More, Pagination마다 장단점이 있지만 e-commerce site의 경우, load more 과 pagination이 더 적합할 것이라고 하였다.

그런데 러쉬코리아의 싸이트는 모든 제품이 한번에 보여지게 되어 있는 것을 확인하고 요즘 트렌드에 맞는 Load More 기능을 추가하고 싶었다.

Infinite scroll을 채택한 페이스북이나, 인스타그램과는 달리 e-commerce site의 경우에는 잠재 구매 고객의 시선이 우리 제품에 더 오래 머무를 수 있는 것이 판매량 증대에 도움이 될 것이라고 생각되었기 때문이다.

그리고 제품 상세 페이지의 상품후기 Pagination을 구현해보고 싶었다.

5. 기록하고 싶은 코드

1) 서버로 데이터를 보내는 장바구니 수량 조절

increaseCount = () => {
    const { selectedProductQtyInCart } = this.state;
    const updateCount = selectedProductQtyInCart + 1;
    this.setState({
      selectedProductQtyInCart: selectedProductQtyInCart + 1,
    });
    this.sendToServer(updateCount);
  };

setState()는 비동기적이다. 비동기적으로 처리되는 함수와 동기적으로 처리되는 함수를 같이 작성하면 의도한 것과 다른 순서로 브라우저에 반영된다.

사용자가 수량을 조절하면 setState로 state에 변화가 생기지만, 이렇게 바로 변화된 값을 가지고 또 서버로 업데이트 내용을 보내는 함수를 실행하면 의도한 수량 값이 전달되지 않는다.

그래서 state의 변경이 발생함 과 동시에 따로 변수를 선언하여 수량을 증가시키고 이 값을 서버에 전달한다.

팀 프로젝트 전 인스타그램 클로닝에서 경험했던 것을 바로 적용할 수 있어서 더 기억에 남는 코드다.

2) 장바구니 총액 계산

calculatePrice = () => {
    const { selectedProductQtyInCart } = this.state;
    const { product, calculateTotalPriceInCart } = this.props;

    const totalPrice = selectedProductQtyInCart * product.price;
    calculateTotalPriceInCart(totalPrice);

    return exchangeCurrency(totalPrice);
  };

state는 중복을 배제하고 최소 집합으로 만들어져야 한다.
총액을 state로 관리할 수 도 있겠지만, React의 원칙대로 DB에서 받아오는 각 제품들의 수량, 금액 정보를 가지고 총액을 계산하는 로직을 Front에서 구현하였다.

3) Utility function

export const exchangeCurrency = price => {
  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'KRW',
  }).format(price);
};

Backend에서 주는 제품의 가격은 단순한 number type으로, 단위 구분이 없다. 이 숫자를 원화로 표시하는 방법을 알아보다가 new Intl.NumberFormat()을 발견하였다. 여러 나라의 통화를 바로 나타내 줄 수 있을 뿐만 아니라, 그 통화에 맞는 단위로 변경도 가능하다.

처음에는 금액이 필요한 모든 곳에서 조금은 복잡해 보이는 이 방법을 사용하였는데, 멘토님의 조언으로 utiliy function으로 따로 빼서 필요한 곳에서 호출하여 사용할 수 있도록 변경하였다.

결과적으로 코드의 가독성이 좋아졌다.

4) 상품 후기 Pagination

export default class Pagination extends Component {
  render() {
    const { reviewsPerPage, totalReviews, paginate } = this.props;
    
    const pageNumbers = [];
    for (let i = 1; i <= Math.ceil(totalReviews / reviewsPerPage); i++) {
      pageNumbers.push(i);
    }

    return (
      <nav>
        <ul className="pagination">
          {pageNumbers.map(number => {
            return (
              <li key={number} className="pageNumber">
                <Link to="#/" className="pageLink"  onClick={() => paginate(number)}>
                  {number}
                </Link>
              </li>
            );
          })}
        </ul>
      </nav>
    );
  }
}

원래 계획은 Backend에서 상품후기 pagination이 가능하도록 하는 것 이였는데, 계획에 변경이 생겨 Frontend에서 구현하게 되었다.

내가 Mock-data로 만든 50개의 상품후기를 한 페이지당 5개씩 보이도록 하여 총 10쪽의 페이지가 생기도록 하였다.

댓글이 증가할 것을 대비하여 페이지 수는 상품 후기의 수와 한 페이지당 보여지는 상품 후기 수에 따라 자동 계산이 될 것이고, 해당 숫자를 클릭했을 때 state로 관리되는 현재 페이이지는 변경이 되면서 해당 페이지로 이동한다.

처음에는 페이지 숫자를 클릭하면 페이지가 바뀌는 것이 아니라 상세 페이지 상단으로 이동하여 문제가 무엇인지 한참을 찾아보다가 <Link to='#/>로 변경하면 해결된 다는 글을 참고하여 적용하였더니 원하는 대로 작동하였다!

Backend 담당자분과 추후에 꼭 DB에서 받은 데이터로 pagaination을 구현하자고 약속하였는데 꼭 이루어졌음 좋겠다.

6. What I learned from this..

칭찬해😎

1) 현란한 state와 props 사용

나는 이제 이 컴포넌트가 어디에 있던 state와 props를 자유자재로 옮겨다니며 쓸 수 있다!

한 페이지에 컴포넌트가 점점 많아지면서 선언했던 state의 위치가 부모 컴포넌트로 또는 할머니 할아버지 컴포넌트로 이동해야 하는 경우가 있었는데, 컴포넌트 트리를 작성하여 state 위치를 결정하니 어렵지 않게 모든 컴포넌트에서 상태관리를 할 수 있었다.

2) Life cycle 이해했음

처음에는 Life cycle이 생소했다. JavaScript에는 없던 개념이라 이 아이를 언제 왜 써야 하는 지 공부를 했는데, 이론적으로 공부한 것을 실제 프로젝트에 연결하는 것이 처음에는 어려웠다.

분명히 DB로부터 componentDidMount를 통해 데이터를 불러왔는데, 그 데이터에 접근하여 특정 데이터를 뽑아오면 에러가 자꾸 발생하는 것이다.

그렇게 몇 시간을 머리를 쥐어 뜯다가 이 에러의 원인은 Life cycle 때문이라는 것을 알게되었다. 으잉?

Constructor단계에서는 비어 있던 데이터가 ComponeneDidMount를 통해 채워진건데, 비어 있는 상태가 존재하는 데이터에 접근하려 하여 에러가 발생했던 것이다.

이를 해결하기 위해 Front에서 조건부 렌더링을 해줘야 했다. 데이터가 확실히 있을 때만 그 데이터에 접근하도록!! 너 이녀석!!!!!!!!!!!!!!!!!!!!!!!!!

이런 개념이 있는 지 조차 모르고 시작했던 프로젝트였는데 나의 머리 숱과 바꾼 귀한 지식이다.

3) Data immutability

온 정성을 쏟아 부었던 장바구니 페이지.

Backend 분들께 요청하여 각 제품의 is_checked: true가 default인 상태로 데이터가 넘어오도록 하였고, 장바구니 상에서 모든 제품이 is_checked: true 면 checkall box도 자동으로 true가 되도록 구상하였다.

문제는, state로 관리 중인 제품의 is_checked 상태가 사용자에 의해 false나 true로 변경되었을 때의 로직이었다.

처음에는 조건문으로 e.target.checked 를 확인하여 state를 변경하였는데, 처음 시도했던 로직은 state를 직접 변경하는 것이 되어 immutability라는 React 대원칙을 어기게 된것이다.

멘토님의 지적으로 해당 로직을 수정하면서 가장 오래 고민했던 만큼 React 대원칙을 다시 한번 마음속 깊이 새기게 되었다.

아쉬워😥

1) 절대적인 부족

시간적으로 프로젝트의 절반이 지난 어느 날, Frontend 1명이 그만두었다.
다른 조보다 원래도 1명이 적은 상태로 시작했었는데, 이제 우리는 Frontend 2명이 된 것이다.

절대적으로 부족한 인원과 시간 속에서 우리는 선택을 해야 했다.

두번째 스프린트 미팅에서 이 팀프로젝트가 누군가에게 멋지게 보이기 위해 진행되는 것이 아니라 Frontend, Backend 모두 그 동안 배웠던 것들을 총동원하여 복습하고 주도적으로 새로운 것을 배워가는 것임에 의미를 두기로 팀원들과 상의를 하고서, 버릴 것은 버리고 취할 것은 취하는 것으로 결정하였다.

예쁨과 기능 욕심을 버리고 필수 기능을 선택하자...ㅠㅠ

비록 Frontend 2명이라는 열악한 조건이었지만 동료 Frontend와 더 똘똘 뭉쳐 끝까지 함께 할 수 있었기에 그 고마움을 다시 한 번 전하고 싶다.

2) Git 사용

인원이 부족해지면서 내가 맡은 페이지가 많아졌다.

특히나 장바구니 기능은 모든 페이지에서 연결이 되어있기 때문에 수정 사안이 생기면 이 컴포넌트 저 컴포넌트 줄줄이 사탕으로 변경이 발생하였다.

그러다보니 code review하는 리뷰어도 혼란스럽고 나도 혼란스러운 상황이 반복되었다.

보통은 이렇게 혼자 많은 페이지를 담당하지는 않기 때문에 어쩔 수 없는 경우라고는 하였지만, 개인적으로 git 사용이 초보여서 더 어려움이 있었던 것 같다.

2차 프로젝트 시작 전에 git을 공부하는 것을 다짐하였다.

3) Refactoring

같은 맥락에서 싸이트다운 싸이트를 만들고, Backend에서 만들어준 데이터를 잘 보여주기 위해 집중하다보니 refactoring이 부족하다고 느꼈다.

특히 반복적으로 사용된 함수는 uitility fucntion으로 관리하면 좋을 것 같은데, 일부만 정리가 된 것이 아쉽다.

2차 프로젝트 중에는 엄두를 못 낼 것 같고, 모든 프로젝트가 끝나면 나의 코드를 되돌아 보며 보다 효과적으로 효율적인 코드로 다듬어야 겠다.

4) Backend와의 소통

돌이켜 생각해보면 아마도 서로가 서로의 영역을 모르는 상태에서 처음 진행된 팀프로젝트여서 인 것 같다.

가장 큰 예로 Backend에서 설정한 key값이 변동이 있을 때에는 Front에 알려주어야 하는데 먼저 전달받은 내용이 없던 것이 아쉬웠다. 갑자기 되던 기능이 안되는 상황이 발생하면 내가 뭘 잘못 작성했나 한참 고민하며 적지 않은 시간을 허비하였는데, 알고보면 Backend쪽의 key값이 소문자에서 대문자로 바뀌었다거나 아예 다른 것으로 바뀐 경우가 있었다.

2차 프로젝트에는 협업 Tool인 Trello를 적극 활용하여 서로의 소중한 시간을 조금 더 생산적으로 쓸 수 있도록 해야겠다.

5) Backend와 함께 철저한 싸이트 분석

처음에는 상대적으로 쉬워보이는 싸이트였다. 그래서 우리 팀은 Front를 다름 팀보다 적게 할당해 준것인가 했는데, 페이지를 하나하나 만들어감에 따라 숨어 있는 기능들이 계속 나타났다.

Backend쪽에서도 Data modeling에 가장 큰 시간이 할애가 되는데 어떤 기능에 어떤 데이터가 필요한 지에 대한 사전 협의가 부족해서 중간에 추가 요청을 하는 상황이 생겼었다.

이 또한 모두 처음이기 때문에 생길 수 밖에 없는 일이었을 것이다.

2차 프로젝트에는 Backend와 함께 철저하게 싸이트를 분석 후 필요한 데이터, 필요한 기능들을 정리하고 시작하면 좋을 것 같다.

profile
If you don't build your dream, someone will hire you to help build theirs.

9개의 댓글

comment-user-thumbnail
2021년 5월 23일

발표때 울컥하신 민정님 모습보고 저도 울컥했어요 ㅜㅜ 민정님,, 정말정말 수고 많으셨어요 👍🏻👍🏻
다음 프로젝트도 같이 화이팅해요!❤️

1개의 답글
comment-user-thumbnail
2021년 5월 23일

갓민정! 갓민정! 갓민정!

1개의 답글
comment-user-thumbnail
2021년 5월 23일

난세의 영웅 민정님! 갓민정!!
민정님 시간은 2주가 아니라 3일 처럼 느껴지셨을것 같아요.. 🥲🥲
그 와중에도 늘 유쾌하셔서 더 감동이었던 민정님!
너무너무 고생많으셨습니다!! 👍🏻👍🏻

1개의 답글
comment-user-thumbnail
2021년 5월 23일

저 하면서 지치려고 할 때마다 아니 민정님 오재님은 둘이서 이걸 어떻게 하고 계신 거지?!?!? 이 생각만 수백번 했어요... 근데 결과물 보고 또 감탄ㅠ.ㅠㅠㅠ 정말 너무너무 고생 많으셨어요 갓민정!!!!!!!👍👍👍👍👍

1개의 답글
comment-user-thumbnail
2021년 5월 26일

두분다 고생 너무 많으셨어요 !!

답글 달기