Skip to content

Conversation

@usageness
Copy link

@usageness usageness commented Jun 9, 2022

안녕하세요, 헤인티!
이번 미션을 끝으로 정말 마지막 리뷰가 되었네요.
드디어 레벨 2가 끝나고 방학을 맞이해서 좋기도 하지만, 한편으로는 끝났다는 생각에 아쉽기도 합니다.

이번 협업 미션 step2 에서는 많은 일들이 있었어요.
백엔드와 함께 api 명세를 만들고, 막상 해보니까 적절하지 않아서 수정하고,
페어와도 이슈에 대해서 함께 고민하고... 길면서도 짧은 시간이었던 것 같아요.
그런 와중에도 다양한 시도를 해보았다는 점에서 스스로에게는 꽤 만족스러운 미션이었습니다!

아래에 이번에 시도했던 것들과 궁금한 점을 정리해보았는데,
헤인티님의 의견은 어떠하신지 알려주시면 감사하겠습니다 :)

그동안 정말 고생 많으셨고, 감사합니다 😊
마지막까지 잘 부탁드려요!


Get Started

이 프로젝트는 서버와의 통신을 기준으로 작성되었으며, 로컬 환경에서만 실행이 가능합니다.
아래 과정을 통해 실행해주세요.

프로젝트 클론하기

git clone https://github.com/usageness/react-shopping-cart-prod
git checkout step2
git pull origin step2

환경변수 파일 생성하기

cd react-shopping-cart-prod // 프로젝트 루트 디렉토리로 이동
touch .env.development

생성한 환경변수 파일에 아래 내용을 입력해주세요.
서버_URL에는 이곳에서 확인한 URL 중 하나를 입력해주세요.

REACT_APP_API_URL=서버_URL

의존성 설치 후 프로젝트 실행

npm i
npm run start

이번에 시도해 본 것

1. 에러 바운더리

만일의 오류 발생에 대비하여, 에러 바운더리를 만들어 적용해주었습니다.

image

시간적인 여유가 부족해서 우선은 만들었다! 에 의의를 두고 라우터 단에서 전체에 적용하였지만,
현재 레이아웃 구조인

<Header />
  /* 페이지 컴포넌트 내용 */
  { children } 
<Footer />

에서 페이지 컴포넌트에 해당하는 헤더와 푸터 사이에 적용하는게 맞다고 생각합니다.
또한 페이지 별로 다른 문제상황에 대응되도록 폴백 컴포넌트도 props으로 받아서 넘겨주면 좋을 것 같아요.

다만 이렇게 하면 <Layout /> 컴포넌트를 불러와 그 사이에 내용을 집어넣는
기존의 페이지 컴포넌트 구조를 모두 뜯어 고치는 대공사가 될 것 같아 눈물을 머금고 포기하였습니다... 😥
너무.. 아쉽네요.. 😭😭😭

2. 컴포넌트 동작 제어를 액션에 위임하기

기존의 액션에서 이미 몇몇 비동기 api들을 이용한 통신과 기타 작업들을 담당하고 있는데,
컴포넌트에서 또 이러한 api들을 불러오고, 스낵바 알림과 같은 처리 과정을 일일히 주고 있는건
그다지 일관되지 않은 구조이고, 컴포넌트에서 알아야 할 정보가 아니라는 생각이 들었습니다.
따라서 컴포넌트에서는 정말 동작에 관한 최소한의 메서드만 호출하고,
기타 통신과 응답에 따른 처리 등을 모두 액션에 넘겨주는 방식을 사용하면 좋을 것 같다는 생각을 했습니다.

const handleWithDrawUser = async (e) => {
    e.preventDefault();
    const withDrawConfrim = confirm(알림_메시지.회원_탈퇴_확인);
    if (withDrawConfrim) {
      const response = await requestWithDrawUser();
      if (response.status === 비동기_요청.SUCCESS) {
        dispatch(snackbar.pushMessageSnackbar('회원 탈퇴에 성공하였습니다!'));
        dispatch(removeUserData());
        navigate('/');
        return;
      }
      dispatch(snackbar.pushMessageSnackbar('회원 탈퇴에 실패하였습니다.'));
    }
};

이랬던 기존의 코드를

const handleWithDrawUser = async (e) => {
    e.preventDefault();
    const withDrawConfrim = confirm(알림_메시지.회원_탈퇴_확인);
    if (withDrawConfrim) {
      const response = await requestWithDrawUser();
      if (response.status === 비동기_요청.SUCCESS) {
        dispatch(withDrawUserSuccess()(navigate));
        return;
      }
      dispatch(withDrawUserFailure());
    }
};

이런식으로 바꾸어주는 리팩토링을 진행하였습니다.
더 나아가서 아예 await 코드가 남지않게

const handleWithDrawUser = async (e) => {
    e.preventDefault();
    const withDrawConfrim = confirm(알림_메시지.회원_탈퇴_확인);
    if (withDrawConfrim) {
      dispatch(withDrawUser()(navigate))
    }
}

이정도 상태까지 바꾸고 싶었지만 하필 이 생각이 PR 마감 20분 전에 떠올라서...
불완전한 리팩토링으로 남아있는 상태입니다. (오히려 일관성이 무너져 버렸네요 😭)
전반적으로 적용하면 컴포넌트 자체가 굉장히 깔끔해질것 같은데,
이렇게 해도 괜찮을지 모르겠어요. 혹시 과도한 추상화일까요...?

3. 통신 전용 객체 "RequestAsync"

이전 step에서도 있었지만, 본격적인 백엔드 통신이 이뤄지며 fetch 요청을 래핑하던
RequestAsync 객체가 조금 더 고도화 되었습니다.
이런식이면 조만간 작은 axios가 될 것 같네요 😅
그냥 axios 같은 라이브러리를 써도 좋지만, 이렇게 하나하나 살을 붙여가며 만드는 것도
재미있는 경험인 것 같아서 개인적으로는 만족스럽습니다!

하지만 실제 프로젝트라면 아무래도 바꾸는게 좋을 것 같다는 생각이 드네요.. 🤔

4. 이 외에 못한것들

일정상의 이슈로 스토리북과 테스트를 현재 상태에 맞게 수정해주지 못했어요.
아마 엄청 깨져있을거라 예상이 되어서... 이 부분은 리뷰에서 제외해주시면 감사하겠습니다 😭

이 외에도 해보진 못했지만 redux의 pending 상태를 사용하는 대신 <React.Suspense /> 도 한 번 적용해보고 싶고,
lazy 를 통해서 코드 분할도 해보고 싶었지만 일정 + 준비 부족으로 다음으로 미뤄두었네요 😅
파면 팔수록 재밌는 기능들이 있어서 이번 step2 리액트 미션들은 즐거운 것 같아요! (보물찾기 하는 느낌이에요)

step2에 수정된 굵직한 내용은 여기까지입니다.
이상한 부분이나 적절하게 보이지 않는 부분이 있다면 마구마구 찔러주시면 감사하겠습니다!


🚩 구현한 요구사항

컴포넌트 구현

  • Input 컴포넌트 구현
  • 로그인 페이지 컴포넌트 구현
  • Icon 컴포넌트 구현
  • ErrorMessage 컴포넌트 구현
  • 회원가입 페이지 컴포넌트 구현
  • 본인확인 페이지 컴포넌트 구현
  • 회원 정보 수정 페이지 컴포넌트 구현
  • 비밀번호 변경 페이지 컴포넌트 구현
  • 스피너 컴포넌트 구현

API

  • MSW를 활용한 유저 API mocking
  • MSW를 활용한 장바구니 API mocking
  • Token기반의 로그인
  • 회원가입
  • 회원 정보 수정
  • 회원탈퇴
  • 비밀번호 수정
  • 장바구니 상품 목록 조회
  • 장바구니 상품 추가
  • 장바구니 상품 수량 변경
  • 장바구니 상품 제거
  • 장바구니 비우기
  • 장바구니 상품 구매

기능

  • 비밀번호 확인 후, 회원정보 수정 페이지로 이동
  • 로그아웃
  • 로그인 시, 유저 아이디를 받아와서 redux에서 관리
    • 로그아웃 시 logout action 호출 (Redux 데이터 삭제)
    • 회원 탈퇴 시 logout action 호출
  • alert -> snackbar
  • confirm -> modal
  • 서버 응답 대기시 스피너 애니메이션 띄워주기
    • redux에서 isPending 상태로 관리하기
  • 비로그인 유저가 로그인이 필요한 url로 접근시 차단하기
  • 장바구니 페이지 이동 시 상품 목록 조회
  • 장바구니 페이지에서 상품 수량 수정
  • 장바구니 페이지에서 상품 선택 삭제
  • 주문하기 버튼 클릭 시 주문 요청
  • 에러 바운더리 적용

usageness added 30 commits June 6, 2022 18:36
@pocojang pocojang marked this pull request as draft June 9, 2022 08:54
@pocojang pocojang requested a review from HyeonaKwon June 9, 2022 08:54
@usageness usageness marked this pull request as ready for review June 9, 2022 16:19
Copy link

@HyeonaKwon HyeonaKwon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

세지님 안녕하세요! 마지막 미션에서 만나뵙네요 :)
백엔드분들과 협업하고 연동하는 과정이 처음이었을텐데 잘 진행되셨던 것 같아 보기 좋네요! 현업에서는 백엔드분들과의 협업은 필수이니 이번 경험을 통해 좋은 경험이 되셨길 바랍니다 👍

말씀주신 내용 중

컴포넌트 동작 제어를 액션에 위임하기

현재는 스낵바가 redux 로 되어있기 때문에 status 와 관련된 코드를 액션으로 옮길 수 있었지만, 응답값에 따라 하위 컴포넌트를 노출/미노출하고 disabled 처리 같은 것들이 필요할 수 있어요! 그래서 완전히 없애기는 힘들거라 생각합니다.

2단계 수행하시느라 고생 많으셨습니다! 구조가 크게 변경되지 않아서 바로 머지해도 될 것 같습니다 💯

const handleWithDrawUser = async (e) => {
e.preventDefault();
const withDrawConfrim = confirm('정말로 탈퇴 하실 건가요?');
const withDrawConfrim = confirm(알림_메시지.회원_탈퇴_확인);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

withDrawConfrim => withDrawConfirm

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 오타가...! 😭😭😭

@HyeonaKwon HyeonaKwon merged commit 0d982ff into woowacourse:usageness Jun 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants