Skip to content

Conversation

@jeschun
Copy link
Collaborator

@jeschun jeschun commented Sep 5, 2025

요구사항

기본

배포 링크

중고마켓

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

중고마켓 반응형

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

심화

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

주요 변경사항

  1. 페이지네이션
  2. 최신순, 좋아요순 드롭다운
  3. 검색기능
    등을 구현했습니다

스크린샷

스크린샷 2025-09-08 오후 7 13 54 스크린샷 2025-09-08 오후 7 14 01 스크린샷 2025-09-08 오후 7 14 05

멘토에게

  • 셀프 코드 리뷰를 통해 질문 이어가겠습니다.

@jeschun jeschun requested a review from kiJu2 September 5, 2025 09:00
@jeschun jeschun self-assigned this Sep 5, 2025
@jeschun jeschun added the 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. label Sep 5, 2025
@kiJu2
Copy link
Collaborator

kiJu2 commented Sep 6, 2025

스프리트 미션 하시느라 수고 많으셨어요.
학습에 도움 되실 수 있게 꼼꼼히 리뷰 하도록 해보겠습니다. 😊

@kiJu2
Copy link
Collaborator

kiJu2 commented Sep 6, 2025

commit 단위를 더욱 자주, 작게 해보시는건 어떠실까요?

git을 다룰 때 commit은 "언제 해야 하는가"를 생각해보신 적 있으신가요?
흔히 하는 말이 있습니다:

커밋은 합칠 수 있지만 나눌 수 없습니다.

그럼 커밋을 언제 해야 할까요?

저는 다음과 같은 룰을 지키며 커밋을 하는걸 권장 드립니다:

  1. 커밋을 하는 단위는 커밋 메시지 한 줄로 설명할 수 있는 행동
  2. 하나의 목표 혹은 액션이 달성될 때

관련하여 읽으시면 좋은 아티클을 추천드릴게요:

tl;dr

관련 변경 사항 커밋
커밋은 관련 변경 사항에 대한 래퍼여야 합니다. 예를 들어 두 개의 다른 버그를 수정하면 두 개의 별도 커밋이 생성되어야 합니다. 작은 커밋을 통해 다른 개발자가 변경 사항을 더 쉽게 이해하고 문제가 발생한 경우 롤백할 수 있습니다. 준비 영역과 같은 도구와 파일의 일부만 준비하는 기능을 통해 Git을 사용하면 매우 세부적인 커밋을 쉽게 만들 수 있습니다.

자주 커밋
커밋은 커밋을 작게 유지하고 관련 변경 사항만 커밋하는 데 도움이 되는 경우가 많습니다. 또한 이를 통해 코드를 다른 사람들과 더 자주 공유할 수 있습니다. 이렇게 하면 모든 사람이 정기적으로 변경 사항을 통합하고 병합 충돌을 방지하는 것이 더 쉬워집니다. 대조적으로, 대규모 커밋을 갖고 이를 드물게 공유하면 충돌을 해결하기가 어렵습니다.

미완성 작업을 커밋하지 마십시오
논리적 구성 요소가 완료된 경우에만 코드를 커밋해야 합니다. 자주 커밋할 수 있도록 기능 구현을 빠르게 완료할 수 있는 논리적 청크로 분할합니다. 깨끗한 작업 복사본이 필요하기 때문에(브랜치 확인, 변경 사항 가져오기 등) 커밋하고 싶은 유혹이 든다면 Git의 «Stash» 기능을 대신 사용하는 것이 좋습니다.

커밋하기 전에 코드를 테스트하세요
완료되었다고 생각하는 일을 저지르고 싶은 유혹에 저항하세요. 철저하게 테스트하여 실제로 완료되었는지, 부작용이 없는지(알 수 있는 한) 확인하세요. 로컬 저장소에 설익은 것을 커밋하려면 자신만 용서하면 되지만, 코드를 다른 사람과 푸시/공유하는 경우에는 코드를 테스트하는 것이 훨씬 더 중요합니다.

원문 보기

@kiJu2
Copy link
Collaborator

kiJu2 commented Sep 6, 2025

커밋 타입도 한 번 고려해보세요 !

tl;dr:

커밋 메시지 형식

type: Subject

body

footer

기본적으로 3가지 영역(제목, 본문, 꼬리말)으로 나누어졌다.

메시지 type은 아래와 같이 분류된다. 아래와 같이 소문자로 작성한다.

| 태그       | 설명                                                       |
|------------|------------------------------------------------------------|
| `feat`     | 새로운 기능 추가                                           |
| `fix`      | 버그 수정                                                  |
| `docs`     | 문서 내용 변경                                             |
| `style`    | 포맷팅, 세미콜론 누락 등 코드 동작에 영향 없는 변경       |
| `refactor` | 코드 리팩토링                                              |
| `test`     | 테스트 코드 작성                                           |
| `chore`    | 빌드 수정, 패키지 설정 등 운영 코드 변경이 없는 작업       |

원문보기

Copy link
Collaborator

Choose a reason for hiding this comment

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

.gitignore를 작성해보시는게 어떨까요?

macos의 압축 과정에서 흔히 .DS_Store 파일이 들어가는 경우가 있습니다.
해당 파일은 프로젝트와 무관하므로 .gitignore에 다음과 같이 작성하시면 git의 추적을 무시할 수 있습니다.

.DS_Store

}) {
const query = `page=${page}&pageSize=${pageSize}&orderBy=${orderBy}&keyword=${keyword}`;
const res = await fetch(
`https://panda-market-api.vercel.app/products?${query}`
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은 따로 정의해두는게 좋겠군요 !

Suggested change
`https://panda-market-api.vercel.app/products?${query}`
`${BASE_URL}/products?${query}`

https://panda-market-api.vercel.app는 앞으로도 계속 사용 될 것이며, 변경될 수도 있기에 따로 정의해볼 수 있습니다 !

더 좋은 방법 ! base URL은 환경 변수에 저장하시는게 좋습니다!

환경 변수(Environment Variable): process.env에 내장되며 앱이 실행될 때 적용할 수 있는 값입니다!

다음과 같이 적용할 수 있습니다:

// .env.development
REACT_APP_BASE_URL="http://localhost:3000"

// .env.production
REACT_APP_BASE_URL="http://myapi.com"

// 사용시
<a href={`${process.env.REACT_APP_BASE_URL}/myroute`}>URL</a>

왜 환경 변수에 저장해야 하나요?

개발(dev), 테스트(test), 실제 사용(prod) 등 다양한 환경에서 앱을 운영하게 되는 경우, 각 환경에 따라 다른 base URL을 사용해야 할 수 있습니다. 만약 코드 내에 하드코딩되어 있다면, 각 환경에 맞춰 앱을 배포할 때마다 코드를 변경해야 하며, 이는 매우 번거로운 작업이 됩니다. 하지만, 환경 변수를 .env.production, .env.development, .env.test와 같이 설정해두었다면, 코드에서는 단지 다음과 같이 적용하기만 하면 됩니다.

const apiUrl = `${process.env.REACT_APP_BASE_URL}/api`;

이러한 방식으로 환경 변수를 사용하면, 배포 환경에 따라 쉽게 URL을 변경할 수 있으며, 코드의 가독성과 유지보수성도 개선됩니다.

실제 코드 응용과 관련해서는 다음 한글 아티클을 참고해보세요! => 보러가기

keyword = "",
}) {
const query = `page=${page}&pageSize=${pageSize}&orderBy=${orderBy}&keyword=${keyword}`;
const res = await fetch(
Copy link
Collaborator

Choose a reason for hiding this comment

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

axios를 사용해보는건 어떨까요?

현재 fetch를 그대로 사용해도 동작은 하겠으나, 반복되는 baseURLfetch로 받은 response에 대한 공통적인 후처리, request 보내기 전 공통적인 처리 등 또한 고려해볼 수 있을거예요.
다음 사항들을 고려해볼 수 있어요:

  1. 만약 get이 아닌 메써드(post, patch, delete 등)일 경우는 어떻게 처리할 수 있을까요?
  2. querybody가 필요할 때는 어떻게 처리 할 수 있을까요?
  3. 로그인 인가를 위한 토큰을 request 전에 자동으로 삽입할 수는 없을까요? (인증/인가를 자동으로 할 수 없을까요?)
  4. 처음 한 번에 Base URL을 지정할 수는 없을까요?
    1. Base URL을 사용하다가 다른 엔드포인트에 요청해야 할 때는 어떻게 할 수 있을까요?
      이 모든 요구사항들을 반영한 아키텍쳐를 구상하기는 어렵습니다. 따라서 이 모든 요구사항이 잘 만족하는 http client를 사용해보시는건 어떨까요 ?

axios 시작하기

Copy link
Collaborator

Choose a reason for hiding this comment

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

어떻게 세팅하면 될까? 🤔

instance를 만들어서 export를 하고 사용해보는 것 정도로 시도해보면 좋을 것 같아요. axios-instance 파일을 만들어서 instance를 생성하고 export한 후 사용해보는건 어떨까요?
다음과 같이 만들어볼 수 있어요:

const baseURL = process.env.NEXT_PUBLIC_LINKBRARY_BaseURL;

const instance = axios.create({
  baseURL: baseURL,
  headers: {
    'Content-Type': 'application/json',
  },
});

export default instance

axios instance

사용 방법 🚀

사용 방법은 정말 간단해요. 다음과 같이 사용할 수 있습니다:

instance.get(`/user/${userId}`)

딱 보니. 마이그레이션도 정말 쉽게 할 수 있겠죠? 😊

axios API

Comment on lines +9 to +11
<Link to="/" className="head_logo">
<img src={Logo} alt="판다마켓 로고" />
</Link>
Copy link
Collaborator

Choose a reason for hiding this comment

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

굿굿 ~ react-router-dom에서 제공하는 Link를 사용하셨군요 👍

Comment on lines +11 to +15
console.log(isTablet, "isTablet");
const { matches: isDesktop } = window.matchMedia(
"screen and (min-width: 1024px)"
);
console.log(isDesktop, "isDesktop");
Copy link
Collaborator

Choose a reason for hiding this comment

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

console.log들은 지워도 될 것 같군요 ! 😉

Suggested change
console.log(isTablet, "isTablet");
const { matches: isDesktop } = window.matchMedia(
"screen and (min-width: 1024px)"
);
console.log(isDesktop, "isDesktop");
const { matches: isDesktop } = window.matchMedia(
"screen and (min-width: 1024px)"
);

const getFilteredData = () => items;
const filteredItems = getFilteredData();

const MAXPAGE = 5;
Copy link
Collaborator

Choose a reason for hiding this comment

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

해당 상수도 컴포넌트 바깥으로 빼는게 좋겠어요 !

리렌더링 시 불필요한 재선언과 컴포넌트 자원을 사용하지 않는 로직을 구분할 수 있게 됩니다 😉

Comment on lines +54 to +55
const getFilteredData = () => items;
const filteredItems = getFilteredData();
Copy link
Collaborator

Choose a reason for hiding this comment

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

혹시 itemsfilteredItems의 내용은 같은거 아닐까요?

Suggested change
const getFilteredData = () => items;
const filteredItems = getFilteredData();

items를 사용하면 될 것 같은데 getFilteredData`를 선언하고 호출하지 않으셔도 될 것으로 보여요 😉


const MAXPAGE = 5;

const focusPage = (n) => document.getElementById(`page${n}`).focus();
Copy link
Collaborator

Choose a reason for hiding this comment

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

혹시 해당 로직이 왜 필요한지 알 수 있을까요 ?

Comment on lines +84 to +98
<button id="page1" onClick={() => goPage(1)}>
1
</button>
<button id="page2" onClick={() => goPage(2)}>
2
</button>
<button id="page3" onClick={() => goPage(3)}>
3
</button>
<button id="page4" onClick={() => goPage(4)}>
4
</button>
<button id="page5" onClick={() => goPage(5)}>
5
</button>
Copy link
Collaborator

Choose a reason for hiding this comment

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

페이지네이션은 동적으로 바뀌어야 합니다 😉

현재 정적으로 5개까지만 보여지는데 현재 활성화 된 페이지에 맞는 페이지네이션이 필요합니다 ! (디자인 시안 참고)

@kiJu2
Copy link
Collaborator

kiJu2 commented Sep 9, 2025

크으... 신천님.. 정말 멋집니다.
결국 이렇게 멋지게 해냈꾼요 🥺🥺🥺🥺 감동의 도가니입니다..
정말 열심히 과제를 수행하신게 몸소 느껴지네요 ㅠㅠ

함께 더욱 더욱 빠르게 성장해봅시다 !
앞으로도 신천님의 성장에 제가 도울 수 있는 일이라면 적극적으로 돕겠습니다 💪💪

스프린트 미션 수행하시느라 정말 수고 많으셨습니다.

@kiJu2 kiJu2 merged commit 066ca20 into codeit-bootcamp-frontend:React-박신천 Sep 9, 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