Skip to content

Conversation

@canofmato
Copy link
Collaborator

요구사항

기본

중고마켓

  • 중고마켓 페이지 주소는 “/items” 입니다.
  • 페이지 주소가 “/items” 일때 상단네비게이션바의 '중고마켓' 버튼의 색상은 “3692FF”입니다.
  • 상단 네비게이션 바는 이전 미션에서 구현한 랜딩 페이지와 동일한 스타일로 만들어 주세요.
  • 상품 데이터 정보는 https://panda-market-api.vercel.app/docs/#/ 에 명세된 GET 메소드 “/products” 를 사용해주세요.
  • '상품 등록하기' 버튼을 누르면 “/additem” 로 이동합니다. ( 빈 페이지 )
  • 전체 상품에서 드롭 다운으로 “최신 순” 또는 “좋아요 순”을 선택해서 정렬을 할 수 있습니다.

중고마켓 반응형

  • 베스트 상품
    • Desktop : 4개 보이기
    • Tablet : 2개 보이기
    • Mobile : 1개 보이기
  • 전체 상품
    • Desktop : 12개 보이기
    • Tablet : 6개 보이기
    • Mobile : 4개 보이기

심화

  • 페이지 네이션 기능을 구현합니다.

주요 변경사항

  • 하단의 pageBar를 5페이지 단위로 구현했습니다.
  • 모바일을 기준으로 디자인을 했습니다.

스크린샷

image
image
image

멘토에게

  • 페이지 네이션 기능을 찾아보면서 하느라 완벽하게 이해를 하지 못한 것 같습니다. 맨 처음 구현을 원했던 것은 5페이지 이후로 하나씩 숫자들이 커지기를 원했는데 그렇게까지 구현이 되지 못한 것 같아 조금 아쉬운 점이 있는 것 같습니다. 특히 Array.from()이 어떻게 활용하는 건지 잘 모르겠습니다.
  • 정렬 버튼을 눌렀을 때 최신순, 좋아요순으로 잘 정렬은 되는데 버튼의 이름?이 바뀌지 않습니다. selection, option을 사용하려다가 모바일버전에서 어려움이 있어 params로 정렬방식을 선택하는 방식으로 했는데, 눌렀을 때 버튼에서의 글씨를 바꿔지게 하려면 어떻게 해야하나요?
  • 셀프 코드 리뷰를 통해 질문 이어가겠습니다.

@canofmato canofmato added the 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. label May 24, 2025
@canofmato canofmato requested a review from addiescode-sj May 24, 2025 13:36
Copy link
Collaborator

@addiescode-sj addiescode-sj left a comment

Choose a reason for hiding this comment

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

수고하셨습니다!
첫미션인데 잘 해주셨네요! 조금만 다듬어보면 멋진 결과물 나올거예요 :)

주요 리뷰 포인트

  • pagination 업데이트 로직 및 유지보수를 고려한 수정
  • DRY 원칙에 따른 코드 중복 제거

@@ -0,0 +1,12 @@
const BASE_URL = "https://panda-market-api.vercel.app";
Copy link
Collaborator

Choose a reason for hiding this comment

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

BASE_URL와 같이 민감한 정보의 경우 일반적으로 외부 공개를 막기위해 환경변수로 관리한답니다. React의 경우 환경변수 설정시 변수명에 REACT_APP_ 접두어가 꼭 필요하니, 아래 아티클 확인해주시고 환경변수 설정해보세요!

참고

const [orderBy, setOrderBy] = useState("recent");
const [itemList, setItemList] = useState([]);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(getPageSize());
Copy link
Collaborator

Choose a reason for hiding this comment

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

useState setter에 window를 참조하고 동기적으로 실행되는 코드를 작성하는 현재 코드는
몇가지의 기술적 배경을 고려한다면 개선하시는게 좋습니다.

다른분 PR에 달아드린 코멘트인데, 참고해보시고 리팩토링해보세요!

#159 (comment)

Comment on lines +74 to +77
<input
className="searchInput"
placeholder="검색할 상품을 입력해주세요"
/>
Copy link
Collaborator

Choose a reason for hiding this comment

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

input (text input field)의 경우 여러 페이지에서 UI가 반복될텐데, 공용 컴포넌트로 만들어 재사용해주면 코드 중복이 줄어들겠죠? :)

Comment on lines +81 to +83
<button className="sortIconButton" onClick={toggleDown}>
<img src={sorticon} alt="정렬버튼" />
</button>
Copy link
Collaborator

Choose a reason for hiding this comment

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

button도 마찬가지! 여러 페이지에서 재사용되는 UI는 공용 컴포넌트로 만들어서 정리하는걸 습관화해봅시다 :)

Comment on lines +103 to +109
<div className="pageNavigationBar">
<PageBar
totalPage={totalPage}
activePage={page}
onPageChange={onPageChange}
/>
</div>
Copy link
Collaborator

Choose a reason for hiding this comment

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

PageNavigationBar 네이밍이 일반적으로 많이 사용하지 않고, 모호한 이름으로 느껴지네요.
보통 페이지네이션을 위한 UI는 Pagination을 많이 사용하는것같아요.

Comment on lines +5 to +17
const getPageSize = () => {
const width = window.innerWidth;
if (width < 768) {
//mobile
return 1;
} else if (width < 1280) {
//tablet
return 2;
} else {
//desktop
return 4;
}
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

이 함수와 pageSize 초기값에 활용하는것까지 바로 위에 있는 AllItemsSection.jsx 에서 작성해줬던것같은데, 코드 중복을 제거하기위해 따로 이 함수부분만 유틸 함수를 쓰거나 state 업데이트까지 고려해 커스텀 훅으로 분리해주는건 어떨까요?

DRY, SOLID 원칙에 대해 공부해보시면 코드를 개선할때 어떤 기준으로 개선하면 좋을지에 대해 도움 받으실수있을거예요 :)
참고

<button
className="pageButton"
disabled={activePage === 1}
onClick={() => setCurrentGroup((prev) => Math.max(prev - 1, 0))}
Copy link
Collaborator

Choose a reason for hiding this comment

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

currentGroup을 업데이트할때 이런식으로 조건에 의해 함수를 따로 만들어 페이지 그룹 전환 로직을 명확하게 분리해볼까요?
페이지 그룹이 실제로 전환되려면 prev, next 버튼을 클릭 시 아래 핸들러를 실행해야할것같아요 :)

  const handlePrevGroup = () => {
    if (currentGroup > 0) {
      setCurrentGroup(currentGroup - 1);
      onPageChange(startPage - maxVisiblePages);
    }
  };

  const handleNextGroup = () => {
    if (currentGroup < maxGroup) {
      setCurrentGroup(currentGroup + 1);
      onPageChange(startPage + maxVisiblePages);
    }
  };

disabled={activePage === 1}
onClick={() => setCurrentGroup((prev) => Math.max(prev - 1, 0))}
>
<img src={leftBtn} alt="왼쪽" />
Copy link
Collaborator

Choose a reason for hiding this comment

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

그리고 버튼 아이콘의 경우 조건에 따라 색깔을 바꾸는 등의 처리가 부가적으로 필요한데, svg 속성의 fill로 바꿔주실 수 있으니 svg를 컴포넌트화해서 props로 넘겨주는 방식은 어떨까요? 아래 예시처럼요 :)

Copy link
Collaborator

@addiescode-sj addiescode-sj May 26, 2025

Choose a reason for hiding this comment

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

  • ArrowIcon을 컴포넌트화해서, 방향과 컬러에 대한 props 넘겨주기
import React from "react";

const ArrowIcon = ({ color = "#000000", direction = "left" }) => {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      style={{
        transform: direction === "right" ? "rotate(180deg)" : "none",
        transformOrigin: "center",
      }}
    >
      <path
        d="M15 18L9 12L15 6"
        stroke={color}
        strokeWidth="2"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  );
};

export default ArrowIcon;

Copy link
Collaborator

Choose a reason for hiding this comment

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

사용 예시:

      <button
        className="pageButton"
        disabled={currentGroup === 0}
        onClick={handlePrevGroup}
      >
        <ArrowIcon
          color={currentGroup === 0 ? "#CCC" : "#000"}
          direction="left"
        />
      </button>

@addiescode-sj
Copy link
Collaborator

질문에 대한 답변

멘토에게

  • 페이지 네이션 기능을 찾아보면서 하느라 완벽하게 이해를 하지 못한 것 같습니다. 맨 처음 구현을 원했던 것은 5페이지 이후로 하나씩 숫자들이 커지기를 원했는데 그렇게까지 구현이 되지 못한 것 같아 조금 아쉬운 점이 있는 것 같습니다. 특히 Array.from()이 어떻게 활용하는 건지 잘 모르겠습니다.

Array.from은 이렇게 작동됩니다!

  • length: 현재 그룹에서 보여줄 페이지 수를 계산
  • (_, i) => startPage + i: 각 배열 아이템을 순회하며, 공통된 작업을 수행 (페이지 번호를 생성) 예를 들어서, startPage가 6이고 maxVisiblePages가 5라면 [6, 7, 8, 9, 10]이 생성됨

startPage 계산이 현재 로직에선 중요한데, 이게 제때 업데이트 안되는 문제가 있었네요 :)

  • 정렬 버튼을 눌렀을 때 최신순, 좋아요순으로 잘 정렬은 되는데 버튼의 이름?이 바뀌지 않습니다. selection, option을 사용하려다가 모바일버전에서 어려움이 있어 params로 정렬방식을 선택하는 방식으로 했는데, 눌렀을 때 버튼에서의 글씨를 바꿔지게 하려면 어떻게 해야하나요?
  • 셀프 코드 리뷰를 통해 질문 이어가겠습니다.

특정 상태에 따라 버튼의 이름이나 스타일이 바뀌어야하는거면 우선 상태가 올바르게 업데이트 되는지 디버깅해보시고 상태에 따른 조건부 렌더링 혹은 스타일링을 할수 있게 구현해주셔야겠죠? :) orderBy state를 관리하시는것같은데, 해당 state의 value를 추적하고 orderBy === "recent" 조건에 의해 리턴문에서 UI 및 스타일링을 분기하면 되겠네요!

@addiescode-sj addiescode-sj merged commit e5de6a2 into codeit-bootcamp-frontend:React-박다인 May 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants