Skip to content

Conversation

@Pheejung
Copy link

@Pheejung Pheejung commented Nov 11, 2025

과제 체크포인트

배포 링크

https://Pheejung.github.io/front-7th-chapter2-1/

기본과제

상품목록

상품 목록 로딩

  • 페이지 접속 시 로딩 상태가 표시된다
  • 데이터 로드 완료 후 상품 목록이 렌더링된다
  • 로딩 실패 시 에러 상태가 표시된다
  • 에러 발생 시 재시도 버튼이 제공된다

상품 목록 조회

  • 각 상품의 기본 정보(이미지, 상품명, 가격)가 카드 형태로 표시된다

한 페이지에 보여질 상품 수 선택

  • 드롭다운에서 10, 20, 50, 100개 중 선택할 수 있으며 기본 값은 20개 이다.
  • 선택 변경 시 즉시 목록에 반영된다

상품 정렬 기능

  • 상품을 가격순/이름순으로 오름차순/내림차순 정렬을 할 수 있다.
  • 드롭다운을 통해 정렬 기준을 선택할 수 있다
  • 정렬 변경 시 즉시 목록에 반영된다

무한 스크롤 페이지네이션

  • 페이지 하단 근처 도달 시 다음 페이지 데이터가 자동 로드된다
  • 스크롤에 따라 계속해서 새로운 상품들이 목록에 추가된다
  • 새 데이터 로드 중일 때 로딩 인디케이터와 스켈레톤 UI가 표시된다
  • 홈 페이지에서만 무한 스크롤이 활성화된다

상품을 장바구니에 담기

  • 각 상품에 장바구니 추가 버튼이 있다
  • 버튼 클릭 시 해당 상품이 장바구니에 추가된다
  • 추가 완료 시 사용자에게 알림이 표시된다

상품 검색

  • 상품명 기반 검색을 위한 텍스트 입력 필드가 있다
  • Enter 키로 검색이 수행된다
  • 검색어와 일치하는 상품들만 목록에 표시된다

카테고리 선택

  • 사용 가능한 카테고리들을 선택할 수 있는 UI가 제공된다
  • 선택된 카테고리에 해당하는 상품들만 표시된다
  • 전체 상품 보기로 돌아갈 수 있다
  • 2단계 카테고리 구조를 지원한다 (1depth, 2depth)

카테고리 네비게이션

  • 현재 선택된 카테고리 경로가 브레드크럼으로 표시된다
  • 브레드크럼의 각 단계를 클릭하여 상위 카테고리로 이동할 수 있다
  • "전체" > "1depth 카테고리" > "2depth 카테고리" 형태로 표시된다

현재 상품 수 표시

  • 현재 조건에서 조회된 총 상품 수가 화면에 표시된다
  • 검색이나 필터 적용 시 상품 수가 실시간으로 업데이트된다

장바구니

장바구니 모달

  • 장바구니 아이콘 클릭 시 모달 형태로 장바구니가 열린다
  • X 버튼이나 배경 클릭으로 모달을 닫을 수 있다
  • ESC 키로 모달을 닫을 수 있다
  • 모달에서 장바구니의 모든 기능을 사용할 수 있다

장바구니 수량 조절

  • 각 장바구니 상품의 수량을 증가할 수 있다
  • 각 장바구니 상품의 수량을 감소할 수 있다
  • 수량 변경 시 총 금액이 실시간으로 업데이트된다

장바구니 삭제

  • 각 상품에 삭제 버튼이 배치되어 있다
  • 삭제 버튼 클릭 시 해당 상품이 장바구니에서 제거된다

장바구니 선택 삭제

  • 각 상품에 선택을 위한 체크박스가 제공된다
  • 선택 삭제 버튼이 있다
  • 체크된 상품들만 일괄 삭제된다

장바구니 전체 선택

  • 모든 상품을 한 번에 선택할 수 있는 마스터 체크박스가 있다
  • 전체 선택 시 모든 상품의 체크박스가 선택된다
  • 전체 해제 시 모든 상품의 체크박스가 해제된다

장바구니 비우기

  • 장바구니에 있는 모든 상품을 한 번에 삭제할 수 있다

상품 상세

상품 클릭시 상세 페이지 이동

  • 상품 목록에서 상품 이미지나 상품 정보 클릭 시 상세 페이지로 이동한다
  • URL이 /product/{productId} 형태로 변경된다
  • 상품의 자세한 정보가 전용 페이지에서 표시된다

상품 상세 페이지 기능

  • 상품 이미지, 설명, 가격 등의 상세 정보가 표시된다
  • 전체 화면을 활용한 상세 정보 레이아웃이 제공된다

상품 상세 - 장바구니 담기

  • 상품 상세 페이지에서 해당 상품을 장바구니에 추가할 수 있다
  • 페이지 내에서 수량을 선택하여 장바구니에 추가할 수 있다
  • 수량 증가/감소 버튼이 제공된다

관련 상품 기능

  • 상품 상세 페이지에서 관련 상품들이 표시된다
  • 같은 카테고리(category2)의 다른 상품들이 관련 상품으로 표시된다
  • 관련 상품 클릭 시 해당 상품의 상세 페이지로 이동한다
  • 현재 보고 있는 상품은 관련 상품에서 제외된다

상품 상세 페이지 내 네비게이션

  • 상품 상세에서 상품 목록으로 돌아가는 버튼이 제공된다
  • 브레드크럼을 통해 카테고리별 상품 목록으로 이동할 수 있다
  • SPA 방식으로 페이지 간 이동이 부드럽게 처리된다

사용자 피드백 시스템

토스트 메시지

  • 장바구니 추가 시 성공 메시지가 토스트로 표시된다
  • 장바구니 삭제, 선택 삭제, 전체 삭제 시 알림 메시지가 표시된다
  • 토스트는 3초 후 자동으로 사라진다
  • 토스트에 닫기 버튼이 제공된다
  • 토스트 타입별로 다른 스타일이 적용된다 (success, info, error)

심화과제

SPA 네비게이션 및 URL 관리

페이지 이동

  • 어플리케이션 내의 모든 페이지 이동(뒤로가기/앞으로가기를 포함)은 하여 새로고침이 발생하지 않아야 한다.

상품 목록 - URL 쿼리 반영

  • 검색어가 URL 쿼리 파라미터에 저장된다
  • 카테고리 선택이 URL 쿼리 파라미터에 저장된다
  • 상품 옵션이 URL 쿼리 파라미터에 저장된다
  • 정렬 조건이 URL 쿼리 파라미터에 저장된다
  • 조건 변경 시 URL이 자동으로 업데이트된다
  • URL을 통해 현재 검색/필터 상태를 공유할 수 있다

상품 목록 - 새로고침 시 상태 유지

  • 새로고침 후 URL 쿼리에서 검색어가 복원된다
  • 새로고침 후 URL 쿼리에서 카테고리가 복원된다
  • 새로고침 후 URL 쿼리에서 옵션 설정이 복원된다
  • 새로고침 후 URL 쿼리에서 정렬 조건이 복원된다
  • 복원된 조건에 맞는 상품 데이터가 다시 로드된다

장바구니 - 새로고침 시 데이터 유지

  • 장바구니 내용이 브라우저에 저장된다
  • 새로고침 후에도 이전 장바구니 내용이 유지된다
  • 장바구니의 선택 상태도 함께 유지된다

상품 상세 - URL에 ID 반영

  • 상품 상세 페이지 이동 시 상품 ID가 URL 경로에 포함된다 (/product/{productId})
  • URL로 직접 접근 시 해당 상품의 상세 페이지가 자동으로 로드된다

상품 상세 - 새로고침시 유지

  • 새로고침 후에도 URL의 상품 ID를 읽어서 해당 상품 상세 페이지가 유지된다

404 페이지

  • 존재하지 않는 경로 접근 시 404 에러 페이지가 표시된다
  • 홈으로 돌아가기 버튼이 제공된다

AI로 한 번 더 구현하기

  • 기존에 구현한 기능을 AI로 다시 구현한다.
  • 이 과정에서 직접 가공하는 것은 최대한 지양한다.

과제 셀프회고

기술적 성장

자랑하고 싶은 코드

개선이 필요하다고 생각하는 코드

학습 효과 분석

과제 피드백

AI 활용 경험 공유하기

리뷰 받고 싶은 내용

Copy link
Contributor

@JunilHwang JunilHwang left a comment

Choose a reason for hiding this comment

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

이 피드백은 n8n + ai (gpt-5-mini)를 활용하여 자동으로 생성된 내용입니다.

  • 데이터와 UI를 연결하는 부분을 보강하면 좋겠습니다. ProductList 내부에 렌더링된 검색/한 페이지 개수/정렬/카테고리/무한스크롤 UI에는 상태와 이벤트 연결이 부족해서 조건을 바꿔도 화면이 갱신되지 않습니다.
  • 에러 처리와 사용자 피드백이 아직 도입되지 않았습니다. main.jscatch 블록은 단순 로그에 그치고, 토스트는 렌더링조차 되지 않아 실패나 장바구니 추가/삭제를 신호로 알려줄 수 없습니다.
  • 그 외에도 장바구니 수량 조절, 상품 상세의 SPA 내비게이션 같은 인터랙션은 현재 템플릿 그대로로는 요구사항을 충족하기 어려우므로 상태/이벤트 중심으로 리팩토링하는 것이 좋겠습니다.

질문에대한 답변

추가 질문이 없어 현재로서는 별도의 답변이 없습니다. 궁금한 점 생기면 언제든 말씀 주세요.

isLoading: false,
products: products,
totalCount: productsData.pagination.total,
categories: categoriesData,
Copy link
Contributor

Choose a reason for hiding this comment

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

문제상황 제시 — API 호출 실패 시 사용자 경험
추가 요구사항에서도 강조되었듯, getProducts/getCategories가 실패하면 사용자에게 재시도가 가능한 에러 UI를 보여줘야 합니다. 그런데 catch 블록은 단순히 console.error만 호출하고 있어 사용자는 로딩 상태 그대로 멈춘 화면만 보게 됩니다.
현재 코드의 한계

  • [한계점 1] 네트워크가 끊기거나 API가 500을 내려도 화면에는 아무 변화가 없고, 사용자에게 실패 메시지가 표시되지 않습니다.
  • [한계점 2] 재시도 버튼이 없어서 사용자가 스스로 새로고침하거나 브라우저를 다시 열기 전에는 서비스를 재시도할 방법이 없습니다.
  • [한계점 3] 화면 상태를 관리하는 로직이 try/catch의 다른 지점과 분리되어 있어, 상태 전이(로딩 → 에러 → 재시도)를 표현하기 어렵습니다.
    근본 원인
    main 함수 안에서 try/catch가 UI 상태와 단일 템플릿 사이에서 직접 제어하는 구조라서, 에러 시 DOM을 다시 그릴 수 있는 추상화가 부족합니다.
    개선 구조
    현재 구조:
Loading view (ProductList – isLoading=true)
└── fetch products/categories
     ├─ success → render ProductList with data
     └─ failure → console.error (no UI change)

개선 후 구조:

Loading view
└── fetch ...
     ├─ success → render ProductList
     └─ failure → render ErrorView + Retry button

개선 사항

  • catch 블록에서 에러 메시지를 담은 상태를 만들어 layout에 다시 넣어서 사용자에게 알려줍니다.
  • 재시도 버튼에 클릭 핸들러를 달아 main을 다시 호출하거나 fetch 로직만 재실행하도록 처리합니다.
  • 에러 상태에서만 보여줄 수 있는 작은 컴포넌트 (예: <ErrorEmptyState onRetry={...} />)를 만들어 구조를 분리합니다.
    코드 비교
// ❌ 현재 방식
  } catch (error) {
    console.error('상품 목록을 불러오는데 실패했습니다:', error);
    // 에러 처리 로직 추가 가능
  }

// ✅ 개선된 방식
  } catch (error) {
    const errorHTML = layout({
      children: () => ErrorView({ message: '상품을 불러오는 데 실패했습니다', onRetry: main }),
    });
    document.querySelector('#root').innerHTML = errorHTML;
  }

.join("");

return `
<!-- 검색 및 필터 -->
Copy link
Contributor

Choose a reason for hiding this comment

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

검색 입력 필드(75~88)를 렌더링하고 있지만 Enter 키나 입력값을 처리하는 로직이 없습니다. 요구사항 중 'Enter 키로 검색'이 명시되어 있으므로 이 input에서 keydown 또는 submit을 감지해서 새로 fetchProducts를 호출해야 합니다. 현재 아무 이벤트가 붙어 있지 않아 검색 결과가 갱신되지 않습니다.
개선 방법:

  • layout이 렌더링된 직후 document.querySelector('#search-input')keydown 핸들러를 등록하고, Enter 키가 눌리면 getProducts({ keyword: input.value })를 재호출합니다.
  • ProductListsearchText prop을 추가해 렌더링 시 값이 유지되도록 하면 새로고침/공유 시에도 검색어가 복원됩니다.

</div>
<!-- 기존 필터들 -->
<div class="flex gap-2 items-center justify-between">
<!-- 페이지당 상품 수 -->
Copy link
Contributor

Choose a reason for hiding this comment

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

#limit-select(106~123)에는 10/20/50/100 옵션만 있고 change 리스너가 없습니다. 따라서 사용자가 페이지당 아이템 수를 바꿔도 화면에는 아무 변화가 없고, 요구사항인 '선택 변경 시 즉시 목록에 반영'이 충족되지 않습니다. 선택값을 감지하여 getProducts({ limit: Number(value) })로 재요청하고 UI를 다시 그려야 합니다.

</option>
</select>
</div>
<!-- 정렬 -->
Copy link
Contributor

Choose a reason for hiding this comment

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

#sort-select(125~134)은 정렬 옵션을 렌더링하지만 change 핸들러가 없기 때문에 정렬 기준을 바꿔도 상품 정렬 순서가 반영되지 않습니다. change 이벤트로 정렬 조건을 상태에 저장한 뒤 getProducts({ sort: 'price_asc' })처럼 다시 호출하고, 받은 데이터를 ProductList에 넘겨주면 요구사항을 만족시킬 수 있습니다.

<!-- 필터 옵션 -->
<div class="space-y-3">
<!-- 카테고리 필터 -->
<div class="space-y-2">
Copy link
Contributor

Choose a reason for hiding this comment

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

카테고리 영역(93~103)은 1단계 버튼만 반복하면서 아무 상태도 관리하지 않습니다. 현재 선택된 카테고리를 알고 있지 않기 때문에 브레드크럼이 갱신되지 않고, 2단계 카테고리도 렌더링되지 않습니다. 요구사항대로 '전체 > 1depth > 2depth' 브레드크럼을 그리고 선택 상태별로 상품을 다시 불러오려면 selectedCategory1/selectedCategory2 상태를 main.js에서 관리하고, 클릭 시 getProducts를 다시 호출하여 ProductList에 전달해야 합니다.

</div>
</div>
<!-- 상품 목록 -->
<div class="mb-6">
Copy link
Contributor

Choose a reason for hiding this comment

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

상품 그리드 영역(140~166)에서는 데이터를 한 번만 렌더링하고 끝나므로 스크롤이 끝까지 내려가도 다음 페이지를 가져오지 않습니다. '홈 페이지에서만 무한 스크롤' 요구사항을 충족하려면 window 또는 #products-grid의 스크롤 이벤트를 감지해 바닥 근처일 때 page 증가시키고 추가 데이터를 products 배열에 push. 로딩 직전에는 Loading()/Skeleton()을 표시하고, isLoading을 상태화하여 여러 번 호출이 겹치지 않도록 제어해야 합니다.

<div class="flex items-center mt-2">
<button class="quantity-decrease-btn w-7 h-7 flex items-center justify-center
border border-gray-300 rounded-l-md bg-gray-50 hover:bg-gray-100" data-product-id="${product.id}">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
Copy link
Contributor

Choose a reason for hiding this comment

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

장바구니 아이템에서 수량 입력(line 25)이 disabled로 막혀 있고 수량 버튼에도 이벤트 연결이 없어, 요구사항인 '수량 증가/감소' 기능이 아예 동작하지 않습니다. 수량 변경 후 전체 금액도 갱신되어야 하므로, input을 활성화하거나 버튼 클릭 시 수량 상태를 변경하고 총합을 다시 계산하는 로직을 추가해 주세요.

<div class="max-w-md mx-auto px-4 py-4">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<button onclick="window.history.back()" class="p-2 text-gray-700 hover:text-gray-900 transition-colors">
Copy link
Contributor

Choose a reason for hiding this comment

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

ProductDetailHeader의 뒤로가기 버튼이 inline onclick 핸들러 (window.history.back(), 59~63)으로 작성되어 있는데, SPA 내비게이션과 일관된 라우터 추상화를 이용하지 않으면 앞으로/뒤로 기능이 분산됩니다. data-action=go-back 같은 식별자를 달고 main.js에서 한 번만 이벤트를 붙여 router.goBack()을 호출하면 테스트하기도 쉽고, 새로 만든 SPA 라우터로도 손쉽게 교체할 수 있습니다.

@@ -0,0 +1,46 @@
const Toast = ({ type = "success", message }) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Toast 컴포넌트(src/components/Toast.js, 1~24)에서는 토스트 메시지의 스타일만 정의하고 실제로 3초 뒤 자동으로 사라지게 하거나 닫기 버튼은 동작하게 하는 스크립트가 없습니다. 요구사항에 '토스트는 3초 후 자동으로 사라지며 닫기 버튼이 제공된다'고 되어 있으므로, setTimeout을 이용해 DOM에서 제거하거나 toastService를 통해 duration을 처리하는 로직을 추가해야 합니다.

// 1. 먼저 로딩 상태 표시
const loadingHTML = layout({
children: ProductList,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

현재 main.js(16~39)에서는 ProductList만 렌더링하고 있으며, Toast 컴포넌트를 DOM에 삽입하거나 버튼 클릭 시 토스트를 보여주는 코드가 전혀 없습니다. 따라서 장바구니 추가/삭제 작업을 해도 사용자는 어떤 피드백도 받지 못합니다. Toast를 렌더링할 <div id='toast-root'>를 만들고, 각각의 버튼 클릭 핸들러에서 Toast를 쌓거나 toastService.show({ type: 'success', message: '...' })를 호출하도록 연결해 주세요.

Copy link

@devchaeyoung devchaeyoung left a comment

Choose a reason for hiding this comment

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

test

Copy link

@devchaeyoung devchaeyoung left a comment

Choose a reason for hiding this comment

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

이 피드백은 n8n + ai (gpt-5-mini)를 활용하여 자동으로 생성된 내용입니다.

희정님 이번 PR에서는 API와 UI를 연결하는 구조가 명확하며, Layout과 컴포넌트를 효과적으로 분리하여 기본 SPA 골격을 잘 조성하셨습니다. 특히 ProductList와 Cart 컴포넌트의 책임 분리가 깔끔한 편입니다. 👍

추가 질문에서 보인 자기 회고 내용은 전반적으로 구현에 대한 깊은 고민이 느껴져서 좋았습니다. 핵심 질문에 대한 답변으로는, 현재 코드 구조가 기능별 컴포넌트 분리는 잘 되어 있지만 상태 관리와 이벤트 로직의 관심사 분리가 다소 미흡해 확장성과 유지보수에 부담이 될 수 있다는 점을 말씀드리고 싶습니다.

전체적으로 컴포넌트 단위의 UI 출력과 API 호출 분리는 잘 되어 있으나, 상태 관리가 충분히 추상화되어 있지 않아 추가 기능 (예: URL 쿼리와 상태 동기화, 무한 스크롤, 장바구니 저장)등 적용 시 복잡도가 증가할 수 있습니다.

질문에대한 답변

1. 질문 요약

희정님은 이번 과제를 통해 자신의 기술적 성장과 구현한 코드에 대해 객관적인 자기 평가를 해주셨고, 코드 설계 및 리팩토링, 그리고 AI 도구 활용 경험까지 상세히 정리해주셨습니다. 리뷰에서는 특히 상태 관리와 모듈화, 이벤트 처리 부분에서 개선 방안을 요청하셨습니다.

2. 현재 선택의 장단점

현재 구조는 UI 컴포넌트가 명확히 분리되어 있어 가독성과 기본적인 책임 분리는 잘 되어 있습니다. 하지만 상태 관리와 DOM 업데이트 로직이 밀접하게 섞여 있어, 상태 변화에 따른 UI 동기화가 수작업으로 이루어지는 점이 확장성을 낮추는 한계입니다. 예를 들어, 장바구니 상태가 중앙에서 통합 관리되지 않으면 모달과 아이콘 표시, 버튼 상태를 일관되게 관리하기 어려워질 수 있습니다.

3. 실무에서라면 이렇게 설계할 것 같아요

  • 상태 관리 분리: 전역 상태 관리 객체(예: store)를 만들어 장바구니, 필터, 검색어 등 상태를 중앙에서 관리합니다.
  • 컴포넌트 분리와 이벤트 위임: UI 구성은 컴포넌트 별로 분리하되, 실제 데이터 변경 로직과 이벤트 처리는 별도의 컨트롤러나 상태 관리 모듈에 위임합니다.
  • URL 상태 동기화: 쿼리스트링과 상태를 연동해서 URL 직접 접근, 새로고침 시 상태 복원이 자연스럽게 이루어지도록 구현합니다.
  • 비동기 처리와 에러 UI 분리: API 호출과 UI 표시를 철저히 분리하며, 에러 상태 표시와 재시도 UI를 명확히 구현합니다.

4. 앞으로 구조를 잡을 때 참고하면 좋은 포인트

  • 관심사 분리를 명확히 하여 UI 템플릿 렌더링을 상태 변경 감지와 분리
  • 상태 관리 및 이벤트 핸들링을 별도의 영역에서 담당하도록 구조 설계
  • 재사용 가능한 유틸리티 함수와 컴포넌트 분리를 통해 코드 중복 최소화
  • 사용자 상호작용에서 발생하는 복잡한 상태 변화를 점진적으로 모듈화하여 유지보수성 증대

희정님 앞으로도 직접 구현하며 이러한 구조적 고민을 이어간다면, SPA 아키텍처 전반에서 한층 더 견고하고 확장성있는 설계를 할 수 있을 것입니다. 응원합니다! 👍

// 아래는 컴포넌트 데모 코드 (개발 참고용)
// ============================================
/*
const 상품목록_레이아웃_카테고리_1Depth = CategoryFilter1Depth({

Choose a reason for hiding this comment

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

희정님, API에서 받은 원시 데이터를 ProductList 컴포넌트가 기대하는 형태로 변환하는 부분이 깔끔하게 처리되어 있습니다 👍 이 부분은 데이터 포맷이 변경되어도 쉽게 대응할 수 있어 확장성에 유리해요.

다만, 이 변환 로직은 여러 곳에서 재사용될 가능성이 크기 때문에 별도의 유틸 함수로 분리해 관리해보면 좋을 것 같아요. 그렇게 하면 데이터 포맷의 변경에 한 곳만 수정하면 되어 유지보수가 편리해집니다.

id: "85067212996",
name: "PVC 투명 젤리 쇼핑백 1호 와인 답례품 구디백 비닐 손잡이 미니 간식 선물포장",
price: 220,
imageUrl: "https://shopping-phinf.pstatic.net/main_8506721/85067212996.1.jpg",

Choose a reason for hiding this comment

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

로딩 시 UI 표시를 layout과 ProductList 컴포넌트를 조합해서 표현하는 구조가 명확하네요. 👍

다만, 에러 발생 시 보여줄 UI와 재시도 버튼 기능은 확인이 어려워 보입니다. 요구사항에 따라 에러 처리를 View에 명확히 반영하고, 재시도 버튼 이벤트를 구현하는 부분을 추가해보면 더욱 완성도가 높아질 것 같아요.

@@ -0,0 +1,162 @@
const CartItem = ({ product, isSelected = false }) => {

Choose a reason for hiding this comment

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

장바구니 모달 컴포넌트가 기능별로 CartItem과 CartModal로 나뉘어져 있어 책임이 잘 분리되어 있습니다. 👍 UI 요소들을 템플릿 리터럴로 깔끔하게 관리한 점도 가독성에 도움이 됩니다.

다만 내부 상태 관리와 이벤트 핸들링이 의존하는 부분이 따로 보여야 유지보수에 유리합니다. 현재의 HTML 생성 코드와 상태나 이벤트 관리를 분리해서 구현할 수 있다면 테스트 및 확장성이 더 좋아질 수 있어요.

const category1Buttons = Object.keys(categories)
.map(
(cat1) => `
<button data-category1="${cat1}" class="category1-filter-btn text-left px-3 py-2 text-sm rounded-md border transition-colors bg-white border-gray-300 text-gray-700 hover:bg-gray-50">

Choose a reason for hiding this comment

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

ProductList 내에서 반복되는 카테고리 버튼 생성 등이 템플릿 리터럴 내에서 처리되고 있는데, 이런 UI 생성 로직을 배열 메서드(map, filter 등)를 활용해 직관적으로 작성한 점이 좋습니다. 👍

하지만 조건에 따라 보여줄 UI가 HTML 문자열 중첩으로 길어지는 부분이 있습니다. 이를 컴포넌트 별 함수로 분리하거나, 간단한 상태 기반 렌더링 함수로 나누어 관리해보는 것도 추천드립니다.

price: 230,
imageUrl: "https://shopping-phinf.pstatic.net/main_8694085/86940857379.1.jpg",
quantity: 1,
},

Choose a reason for hiding this comment

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

전체적으로 SPA 구조를 손수 구현하시면서 Layout, Component, API 연동을 명확히 분리해두셨네요. 👍 하나의 main.js에서 데이터를 fetch하고, 레이아웃에 따라 UI를 업데이트하는 구조가 잘 구현되어 있습니다.

다만, 상태 관리 (검색어, 카테고리 필터 상태, 장바구니 상태 등)를 전역적으로 분리하는 작업이 필요해 보입니다. 상태가 분산되어 있으면 사용자 상호작용에 대한 이벤트 처리와 상태 동기화가 복잡해질 수 있기 때문입니다.

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.

3 participants