Skip to content

Conversation

@hhjin1
Copy link
Collaborator

@hhjin1 hhjin1 commented Mar 12, 2025

요구사항

기본

  • [] 상품 상세 페이지 주소는 "/items/{productId}" 입니다.

  • response로 받은 아래의 데이터로 화면을 구현합니다

  • [x]favoriteCount : 하트 개수

  • [x]images : 상품 이미지

  • tags : 상품 태그

  • name : 상품 이름

  • description : 상품 설명

  • 목록으로 돌아가기 버튼을 클릭하면 중고마켓 페이지인 주소 "/items"으로 이동 합니다

  • 문의하기에 내용을 입력하면 등록 버튼의 색상은 "3692FF"로 변합니다.

  • response로 받은 아래의 데이터로 화면을 구협합니다

  • image : 작성자 이미지

  • nickname : 작성자 닉네임

  • content : 작성자가 남긴 문구

  • description : 상품 설명

  • updatedAt : 문의글 마지막 업데이트 시간

심화

  • [] 모든 버튼에 자유롭게 Hover효과를 적용하세요.

멘토에게

  • 상품 상세 페이지 주소는 "/items/{productId}" 입니다. 이 부분을 놓쳤습니다ㅜㅜ 추후에 적용하겠습니다.
  • 셀프 코드 리뷰를 통해 질문 이어가겠습니다.

@hhjin1 hhjin1 self-assigned this Mar 12, 2025
@hhjin1 hhjin1 added the 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. label Mar 12, 2025
@kiJu2
Copy link
Collaborator

kiJu2 commented Mar 13, 2025

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

Comment on lines +17 to +23
<Header />

<div className="withHeader">
<Routes>
{/* React Router v6부터는 path="/" 대신 간단하게 `index`라고 표기하면 돼요 */}
<Route index element={<HomePage />} />
<Route path="login" element={<LoginPage />} />
<Route path="items" element={<MarketPage />} />
<Route path="additem" element={<AddItemPage />} />
<Route path="community" element={<CommunityFeedPage />} />
</Routes>
</div>
</BrowserRouter>
<div className="withHeader">
<Routes>
{/* React Router v6부터는 path="/" 대신 간단하게 `index`라고 표기하면 돼요 */}
<Route index element={<HomePage />} />
<Route path="login" element={<LoginPage />} />
Copy link
Collaborator

Choose a reason for hiding this comment

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

오잉 ? 혹시 로그인 페이지에서는 Global Navigation Bar가 없지 않나요?

만약 그렇다면 react-router-dom에서 outlet을 활용해볼 수 있습니다 !
Routes에서 element를 지정하여 중첩 레이아웃을 사용할 수 있으니 참고해서 설계해보세요 😊

tl;dr

// App.tsx
<Routes>
  <Route path="/" element={<Main />}> // 중첩 라우팅
    <Route path="user-management" element={<UserManagement />} />
    <Route path="child-management" element={<ChildManagement />} />
  </Route>
  <Route path="/login" element={<Login />} />
</Routes>
// Main.tsx
<MainWrapper>
  <MainMenu />
  <Outlet /> // children과 같은 효과 ! ✨
</MainWrapper>

[React] React-router 'Outlet' 사용하여 레이아웃 구성하기

react-routes-dom/layout

Comment on lines +4 to +5
const BASE_URL = process.env.REACT_APP_BASE_URL;

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 +6 to +12
export async function getComments(productId) {
const response = await axios.get(
`${BASE_URL}/products/${productId}/comments?limit=3`
);

return response.data.list || [];
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

limit을 고정하지 않고 기본값으로 넣는게 더 유연한 API 함수가 될 것 같아요 😊

Suggested change
export async function getComments(productId) {
const response = await axios.get(
`${BASE_URL}/products/${productId}/comments?limit=3`
);
return response.data.list || [];
}
export async function getComments(productId, limit = 3) {
const response = await axios.get(
`${BASE_URL}/products/${productId}/comments?limit=${limit}`
);
return response.data.list || [];
}

Comment on lines +7 to +9
const response = await axios.get(
`${BASE_URL}/products/${productId}/comments?limit=3`
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

쿼리는 URLSearchParams로 손쉽게 사용할 수 있어요 !

Suggested change
const response = await axios.get(
`${BASE_URL}/products/${productId}/comments?limit=3`
);
const params = new URLSearchParams({ limit: '100' });
const { data } = await axios.get(`${BASE_URL}/products/${productId}/comments`, { params });

axios를 사용하실 경우 URLSearchParams와 함께 객체로 손쉽게 핸들링할 수 있습니다 !
객체로 구성할 수 있어 가독성이 좋고, URL 인코딩을 자동으로 처리하여 특수 문자나 공백이 포함된 값에서도 안전하게 동작합니다 !

URLSearchParams: URLSearchParams 인터페이스는 URL의 쿼리 문자열을 대상으로 작업할 수 있는 유틸리티 메서드를 정의합니다.

쿼리를 생성하실 때에 참고해서 사용해보세요 😊

@@ -0,0 +1,12 @@
//commentApi.js
import axios from "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

인가에 필요한 accessTokenlocalStorage가 있다면 axios의 인터셉터를 활용할 수 있습니다 !

인터셉터는 혼자 해결해보시는 것을 권장드립니다. 혹시 모르시겠으면 다음 위클리 미션에 질문해주세요. 😊

Copy link
Collaborator

Choose a reason for hiding this comment

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

해당 버튼은 htmlcss로 만드는게 어떨까요 ?!

Comment on lines +21 to +28
fetch(
`https://panda-market-api.vercel.app/products/${productId}/comments?limit=10`
)
.then((res) => res.json())
.then((data) => {
setComments(data.list || []);
})
.catch(console.error);
Copy link
Collaborator

Choose a reason for hiding this comment

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

api 함수를 이미 만드셨으므로 해당 컴포넌트에서 fetch를 할 필요가 없어보입니다 !

다음과 같이 작성해볼 수 있겠네요 !

Suggested change
fetch(
`https://panda-market-api.vercel.app/products/${productId}/comments?limit=10`
)
.then((res) => res.json())
.then((data) => {
setComments(data.list || []);
})
.catch(console.error);
getComments(productId, 10) // 만약 상기 getComments limit에 대한 피드백을 수용했을 경우 두번째 파라메터가 붙습니다 !

@kiJu2
Copy link
Collaborator

kiJu2 commented Mar 13, 2025

수고하셨습니다 혜진님 !!
요새 과제와 학습을 열심히 하시는 것 같아서 너무 기쁘네요 ㅠㅠㅠㅠ
점차 리며드는 것도 느껴지구요 ㅎㅎㅎ 타입스크립트도 어떻게 풀어내실지 기대가 되는군요 !
api 함수에 관련하여 조금 상세히 피드백 드려봤어요 ! 여유 되실 때 한 번 적용해보셔도 좋을 것 같아요 !

과제 수행하시느라 정말 수고 많으셨습니다 혜진님 !

@kiJu2 kiJu2 merged commit 38f3414 into codeit-bootcamp-frontend:React-황혜진 Mar 13, 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