새소식

우테코

[우테코 FE 6기] 레벨2 미션4 상품 목록 미션 회고 🛍️

  • -
반응형

 

 


벌써 레벨 2 마지막 미션이다. 시간이 참 빨리 지나갔다.


 

이번 상품 목록의 📍 학습 목표

step1

✔️ MSW를 사용하여 API 요청을 모킹 하고 개발한다.

✔️ 비동기 작업(API 요청)의 상태를 관리하고, 비동기 요청 상태에 따라 적절한 UI를 보여줄 수 있다.

✔️ RTL을 사용하여 비동기 작업에 대한 테스트를 작성할 수 있다.

step2

✔️ React Query를 사용하여 서버 상태를 관리할 수 있다.🛍️

✔️ API 연동 과정에서 발생하는 다양한 에러 상황에 대응하고 사용자에게 피드백을 제공할 수 있다.

 

이번 미션에서 나는 무얼 배우고, 어떤 것에 집중해서 작업해 보았을까?

 


 

 

🔎 MSW 사용하여 테스트 코드 작성하기

 

이번 미션을 통해 MSW라는 걸 배우게 되었다.

 

MSW란?

MSW(Mock Service Worker)는 프론트엔드 개발자가 API 통신을 모킹(mocking)하기 위해 사용하는 도구이다. 주로 프론트엔드 개발 환경에서 서버와의 통신을 모방하여 실제 백엔드 서버 없이도 API 호출을 테스트할 수 있게 도와준다.

 

MSW는 서비스 워커(Service Worker)를 사용하여 네트워크 요청을 가로채고, 미리 정의된 모킹 핸들러에 따라 응답을 반환하는 것이다.

 

이 때문에 프론트 개발자는

  1. 독립적인 프론트엔드 개발: 백엔드가 완성되지 않은 상태에서도 프론트엔드 개발을 진행할 수 있다.
  2. 안정적인 테스트 환경: 외부 API의 상태나 네트워크 상황에 영향을 받지 않고 일관된 테스트 결과를 얻을 수 있다.
  3. 빠른 피드백 루프: API 응답을 빠르게 수정하고 테스트할 수 있어 개발 속도가 빨라진다.

 

이렇게 MSW를 활용해서 테스트 코드를 작성하여 기능 구현이 잘되고 있는지 백엔드 연결 없이도 확인할 수 있었다.

 

물론 처음에는 습관이 안 들어서 모킹 핸들러를 수정하지도 않고 테스트를 진행해서 말도 안 되는 결과에 삽질도 했었다. 하지만 이런 과정이 있기 때문에 많은 교훈을 얻은 게 아닐까…?

 


 

🤔 프론트 관점에서의 테스트 시나리오 작성하기

이렇게 열심히 테스트 코드를 짰다. 그럼 과연 모두 좋은 테스트 코드인 걸까?

아니었다.

 

 

 

리뷰어의 이 코멘트를 통해 내가 작성한 테스트에 대해 다시 한번 생각해 볼 수 있었다.

 

내가 작성한 테스트는 기능에 초점이 많이 맞춰있었다. 하지만 이 테스트가 도움이 되는 테스트였나?

아니다.

 

코멘트 달아주신 말처럼 백엔드에서 넘어올 데이터를 검증할 필요는 없다.

우리가 검증해야 할 것은 차라리 어떤 api를 호출하고 있는지를 확인하는 편이 더 맞았을 것 같다고 생각이 든다. 또는 UI 적으로 선택한 카테고리로 보이고 있는지 등을 검증하는 것이 더 프론트에게 필요한 테스트였지 않을까 생각이 들었다.

 

어쩌면 나는 TDD에 너무 집착한 나머지 많고 다양한 케이스의 테스트 케이스 === 좋은 테스트 코드라고 착각한 게 아닐까 싶다.

 

이 이후로는 이게 정말 프론트 관점에서 도움이 되고 피드백받으면 좋은 부분인가를 한번 더 생각해 보게 된 좋은 코멘트였던거 같다.

((역시 킹갓하루..))


💅 ul, li Tag 사용해서 드롭다운 만들기

 

이전 미션에서는 select와 option 태그를 사용해서 화면을 구현했었다. 하지만 option 태그의 단점 중 하나는 스타일을 정의할 수 없다는 점이 매우 불편했다. 그래서 이를 해결하기 위해 직접 ul, li 태그를 활용하여 베이스 드롭다운 버튼을 만들었다.

 

스타일을 모두 작성하는 것과 모바일에 적용되지 않은 호버 기능 등 때문에 꽤 시간이 걸렸지만, 그래도 직접 스타일을 정의하여 만드니 일반 UI보다 통일감도 있고 예뻐서 마음에 들었다.

 

 

option 사용 vs ul 사용 ((훨씬 예쁘다 아니면 말고))

 

 


⛑️ 카테고리 필터링 및 정렬을 적용한 api 호출하기

이제 드롭다운으로 선택한 필터링 카테고리와 정렬을 적용한 데이터를 호출해보려고 한다.

 

URLSearchParams(); 를 활용하여 쿼리문을 만들어보았다.

아래 코드처럼 카테고리 설정 유무, 필터링 설정 유무, 페이지 번호, 가져오려는 개수 사이즈 등을 전달받아 각각 필요한 쿼리문을 만들어주었다.

const buildGetProductListURL = ({
  baseUrl,
  category,
  page,
  size,
  order,
}: Props): string => {
  const params = new URLSearchParams();

  if (category) {
    params.append('category', category);
  }
  if (page !== undefined) {
    params.append('page', String(page));
  }
  if (size !== undefined) {
    params.append('size', String(size));
  }

  const sortOrder = order === 'desc' ? 'price,desc' : 'price';
  params.append('sort', sortOrder);
  params.append('sort', 'name');

  const queryString = params.toString();
  return queryString ? `${baseUrl}?${queryString}` : baseUrl;
};

 

 

 

그리고 이 로직을 endpoint 내에 바로 만들기엔 너무 복잡하다고 판단하여 따로 함수로 분리하여 endpoint에 넣어줬다.

product: {
    getList: ({ page, size, category, order }: getProductListProps) => {
      return buildGetProductListURL({
        baseUrl: `/products`,
        page,
        size,
        category,
        order,
      });
    },                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

 

🦄 Intersection Observer API 사용해서 무한스크롤 사용

 

이번 미션은 무한 스크롤 기능을 사용하여 새로운 데이터를 불러와야 했기 때문에 Intersection Observer API를 사용해서 작업해 보았다.

추가하는 과정은 이전에 한번 해봐서 그런지 크게 어렵지 않았다.

 

하지만 발견된 버그는 초기 마운트될 시 페이지 0인 데이터가 불러오기 전에 observer 가 되어서 새로운 데이터가 불리는 버그가 발생했다.

이 레이아웃에서 보이는 것처럼 초기 데이터가 없으면 다음 페이지 호출을 위해 만들어놓은 div가 관찰되기 때문이었다.

 

이를 해결해 주기 위해 리스트 컨테이너의 최소 사이즈를 지정해 주었다.

 

해결 완료 ~!!

 


 

 

그리고 시작된 step2 기능 구현

 

🥝 리액트 쿼리 사용해서 상태 관리

이전에 useState와 useEffect를 활용하여 커스텀 훅으로 구현해 놓은 기능을 리액트 쿼리를 사용해서 모두 개선해 보는 미션이었다.

이전에 리액트 쿼리는 사용해 본 적 있었는데 useMutation 은 처음 사용해 보아서 내가 리액트 쿼리를 정말 10%만 활용했었구나라고 생각이 들었다.

 

가장 좋았던 기능은 아무래도 invalidateQueries를 사용하여 자동으로 쿼리를 재 실행할 수 있는 기능이 아닐까 싶다. 이 기능을 활용해서 새로운 데이터가 추가되거나, 수정, 삭제되었을 때 리스트 데이터를 다른 기능 구현 없이 다시 fetch 해올 수 있었다.

 

// 관련 코드가 중복되어 커스텀 훅으로 분리해본 invalidateQueries 관련 커스텀 훅 
import { QUERY_KEYS } from '@/constants/queryKeys';
import { useQueryClient } from '@tanstack/react-query';

const useRefetchGetCartList = () => {
  const queryClient = useQueryClient();

  const invalidateCartQuery = () => {
    queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.CART] });
  };

  return {
    invalidateCartQuery,
  };
};

export default useRefetchGetCartList;

 


 

🥐 리액트 쿼리 사용해서 무한 스크롤 기능 구현

 

그리고 이전에 만든 무한 스크롤 기능을 useInfiniteQuery를 활용하여 개선해 보았다.

 

useInfiniteQuery란?

useInfiniteQuery는 React Query 라이브러리에서 제공하는 훅 중 하나로, 무한 스크롤이나 페이지네이션 기능을 손쉽게 구현할 수 있게 도와준다.

 

이 훅은 데이터 페칭과 캐싱, 상태 관리 등을 자동으로 처리해 주어 매우 간단하게 무한 스크롤 기능을 구현할 수 있도록 도와주었다.

 

기능으로는

  1. 자동 페이지 관리: 새로운 페이지를 불러올 때마다 현재 페이지와 다음 페이지를 자동으로 관리해 준다.
  2. 캐싱: 불러온 데이터를 캐시에 저장하여 동일한 데이터를 다시 요청하지 않는다.
  3. 에러 핸들링: 네트워크 오류나 데이터 불러오기 실패 시 자동으로 에러 상태를 관리해 준다.
  4. 로딩 상태 관리: 데이터가 로딩 중인지 여부를 쉽게 확인할 수 있다.

 

이 쿼리는 정말 혁신적인 쿼리였다. 개발자가 따로 새로운 페이지를 불러오거나 복잡한 상태 관리를 직접 해줄 필요 없이, 모든 작업을 하나의 훅으로 완성할 수 있었다.

 

리액트 쿼리를 통해 무한 스크롤 기능을 개선하면서, 데이터 페칭 및 상태 관리의 편리함을 새삼 느꼈다. 앞으로 더 많은 프로젝트에서 리액트 쿼리를 활용하여 더욱 효율적일 거 같다.

 


 

 

🍕 장바구니를 모달 이전에 만든 라이브러리를 활용하기

이번 미션도 마찬가지로 페이먼츠 모듈 미션에서 제작한 모달 라이브러리를 사용하여 모달을 작성했어야 했다.

매번 사용할 때마다 느끼지만 과거의 내가 잘못한 일 때문에 미래의 내가 고생한다.

하..

 

합성 컴포넌트를 사용하여서 크게 문제는 없었지만 자잘한 사이즈 문제, 컬러 변경 문제 때문에 약간의 수정이 필요했다.

 

이젠 더 이상 이 라이브러리를 수정하는 일이 없었으면 좋겠다.

((더 이상 안사용하고 싶다는 말보다는 이젠 완성된 버전이었으면 좋겠다는 뜻))


 

🦋 기타 등등 작업해 본 부분

 

  1. 에러 토스트 띄우기

 

에러 토스트

 

 

2. 장바구니가 비었거나, 상품 목록이 없을 때 UI 처리 추가하기

 


Github

 

GitHub - healim01/react-shopping-products

Contribute to healim01/react-shopping-products development by creating an account on GitHub.

github.com

 

배포 사이트 

 

react-shopping-products

 

healim01.github.io

 

 

 

 

이번 미션도 정말 많은 걸 배우고 실험해 본 미션이었던 거 같다.

정말 재미있었다.

반응형
Contents
-

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.