과제 체크포인트
배포 링크
기본과제
상품목록
상품 목록 로딩
- 페이지 접속 시 로딩 상태가 표시된다
- 데이터 로드 완료 후 상품 목록이 렌더링된다
- 로딩 실패 시 에러 상태가 표시된다
- 에러 발생 시 재시도 버튼이 제공된다
상품 목록 조회
- 각 상품의 기본 정보(이미지, 상품명, 가격)가 카드 형태로 표시된다
한 페이지에 보여질 상품 수 선택
- 드롭다운에서 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로 다시 구현한다.
- 이 과정에서 직접 가공하는 것은 최대한 지양한다.
과제 셀프회고
기술적 성장
SPA를 만들어야하기 때문에 라우터를 직접 구현해야 했고 그 과정에서 히스토리 API에 대해 알게됐으며, event listenr로 생성한 이벤트는 클린업을 해주지 않으면 이벤트가 중복 생성되는 등 프레임워크를 사용할 때 고려하지 않았던 불편함을 직접 마주했습니다.
export async function render() {
const root = document.querySelector("#root");
const { pathname } = location;
// 경로만 사용하도록 쿼리스트링 제거
const cleanPath = pathname.split("?")[0];
const pageFn = URL_MAP[cleanPath] || notFoundPage;
// 페이지를 그냥 async로 만들어서 사용
const content = await pageFn();
root.innerHTML = content;
if (typeof pageFn.afterRender === "function") {
pageFn.afterRender();
}
}
자랑하고 싶은 코드
사실 만족스러운 부분은 없습니다. 억지로 뽑아보자면 라우터 부분인데 잘 짠 코드는 아니지만 가독성은 나쁘지 않은 것 같습니다.
// path별 페이지 상수로 관리
const URL_MAP = {
[ROUTES.MAIN]: productPage,
[ROUTES.PRODUCT]: productPage,
[ROUTES.PRODUCT_DETAIL]: productDetailPage,
[ROUTES.CART]: cartPage,
[ROUTES.ERROR]: notFoundPage,
};
// replace할지 push할지 인자로 받은후 해당 경로로 이동후 랜더링
export async function navigate(pathname, replace = false) {
history[replace ? "replaceState" : "pushState"](null, "", getFullPath(pathname));
await render();
}
// 해당 경로에 맞는 페이지 불러온 후 root innerHTML변경
export async function render() {
const root = document.querySelector("#root");
const { pathname } = location;
// 경로만 사용하도록 쿼리스트링 제거
const cleanPath = pathname.split("?")[0];
const pageFn = URL_MAP[cleanPath] || notFoundPage;
// 페이지를 그냥 async로 만들어서 사용
const content = await pageFn();
root.innerHTML = content;
if (typeof pageFn.afterRender === "function") {
pageFn.afterRender();
}
}
개선이 필요하다고 생각하는 코드
각 페이지 랜더링후 이벤트리스너 생성하는데... 다른분들처럼 이벤트위임 방식으로 한번에 관리하고 클린업 했으면 더 좋았을 것 같다.
productPage.afterRender = () => {
const searchInput = document.getElementById("search-input");
const limitSelect = document.getElementById("limit-select");
const sortSelect = document.getElementById("sort-select");
const productGrid = document.getElementById("products-grid");
if (searchInput) {
searchInput.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
const params = new URLSearchParams(location.search);
params.set("search", e.target.value.trim());
params.set("page", 1); // 검색 시 페이지 초기화
navigate(`${location.pathname}?${params.toString()}`);
}
});
}
if (limitSelect) {
limitSelect.addEventListener("change", (e) => {
const params = new URLSearchParams(location.search);
params.set("limit", e.target.value);
params.set("page", 1);
navigate(`${location.pathname}?${params.toString()}`);
});
}
// ... 위와 동일한 로직 반복
학습 효과 분석
가장 큰 배움이라 함은 도구 맞춤형 개발자가 되지 않으려면 CS지식이 필요하다는 것 이번주 과제에서 배운 히스토리 api, 이벤트 위임, clean up, mount, unmount 등 배운것에 대한 지식에 대한 정리를 할 예정 실무에서 프레임워크 사용 없이 spa를 구현할 일은 없지만 프레임워크를 사용하지 않는 라이트한 시스템을 개발해야한다면 이번에 배운 지식을 사용할 수 있을것 같다. => 그 외에는 생산성을 폭발적으로 올려주는 도구를 적극 활용할 것 같습니다.
과제 피드백
바닐라 자바스크립트를 사용해본적이 많이 없어서 불편했다. 사실 ts를 사용해도 된다고 하셨는데 과제에는 큰 영향을 주지 않았을 것 같다. 과제를 하면서 DOM을 직접 핸들링하는게 오랜만이었고 시대를 역행하는 느낌...? 라이브러리나 프레임워크에 대한 고마움이 커졌다. 그래도 알고 쓰는 것과 모르고 쓰는 것에 차이는 확실히 있고 이번에 한 과제를 설명하라고 하면 설명은 할 수 있을 것 같습니다.
AI 활용 경험 공유하기
chat GPT를 활용했는데 모르는게 있을 때 마다 질문하는 식으로 사용해서 효율성은 그닥 좋지 않았던 것 같습니다. 다른분들은 설계를 먼저하고 베이스 컴포넌트 개발을 AI를 시켰다는데 저도 다음에 참고 할 예정입니다.
리뷰 받고 싶은 내용
-
클래스를 사용하는 이유가 궁금합니다. 개발을 하다보면 결국 객체지향형 프로그래밍을 하게 된다는데 클래스를 사용하지 않더라도 객체 지향적으로 개발하면 되지 않나요?
-
ai를 잘 쓰는 방법이 궁금합니다. 제가 줏대가 없는걸지도 모르겠는데 "AI한테 알려주고 시키는 것도 실력이다.", "AI가 다 하면 나는 대체 가능한 사람이 되는 건데...그러면 어떤 개발자가 되야하는가" 이런 생각이 공존하는 것 같습니다. 제가 최근 경험을 예시로 들면 최근 프로젝트에서 shardcn이라는 component/ui를 사용하게 되면서 반복적으로 작업하는 코딩은 ai를 시켜서 작성하고 주요 로직을 구현하는 쪽으로 진행을 하려고 했는데... 그렇게 되면 다른 누군가에게 shardcn사용 경험이 있다고 말 할 수 있을까?라는 생각이 들더라고요. 이것에 대한 테오의 생각이 궁금해요
-
얼마전 멘토링에서 FE는 생각보다 빨리 고점에 도달한다고 하셨는데... 이부분 동의 합니다. 제가 물론 고점을 찍을 수 있을지는 모르겠지만 FE는 조만간 AI로 대체가 될거라고 생각해요. 그러면 BE로 가야하는가? 라고하면 그건 너무 단순한 발상인 것 같습니다. 개발자라는 직업으로 먹고 사는게 그렇게 전망이 좋아보이진 않습니다. 테오는 어떻게 생각하세요?
-
코드가 전반적으로 구조를 잘 짰다고 보기엔 어려운 것 같습니다. 하지만 제가 회사에서 사용하는 작성법과 크게 다르냐 하면 아닌 것 같습니다. 그런부분에서 봤을 때 구조를 잘 만들려면 어떤 부분을 고려해서 만들어야하는지 3가지만 알려줄 수 있을까요?