-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[진성진] Sprint 5 #64
The head ref may contain hidden characters: "React-\uC9C4\uC131\uC9C4-sprint14"
[진성진] Sprint 5 #64
Conversation
[Fix] delete merged branch github action
…-sprint1 [진성진] Sprint1
…진-sprint2 [진성진] Sprint 2
…진-sprint4 Basic 진성진 sprint4
- install react-router-dom
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
성진님 이번 미션도 고생 많으셨습니다! 💯
기본적인 리엑트 개념 이해도 충분히 잘 하고 계신 거 같고 어떻게 하면 더 나은 코드를 작성할 지 고민하시는 모습이 너무 좋습니다 👍 👍 👍 여유가 되신다면 컴포넌트 재사용성에 대해 고민해보시면 더욱 좋을 거 같아요!
return ( | ||
<div className={styles.main_center}> | ||
<article className={styles.best_items_container}> | ||
<p className={styles.title}>베스트 상품</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p tag는 단락을 나타내므로 여기서는 맞지 않겠네요 :)
}, | ||
}; | ||
|
||
const useItemPageState = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
벌써 커스텀 훅을 활용하시는군요! 👍 👍
?.sort((a, b) => b.favoriteCount - a.favoriteCount) | ||
.slice(0, currentBestItemsAmount) ?? []; | ||
|
||
const typingKeywordChangeHandler = debounce((e) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
debounce도 적용해 주셨네요! 😮
const sortBy = searchParams.get("sortBy") || "recent"; | ||
const keyword = searchParams.get("keyword") || ""; | ||
|
||
const bestItemList = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
정렬, 분류 등은 보통 서버를 활용합니다. 지금은 전체 상품에서 가장 인기 있는 제품이 아니라 현재 페이지에서 가장 인기 있는 상품을 렌더링하고 있습니다! 😢
}; | ||
|
||
const useItemPageState = () => { | ||
const [searchParams, setSearchParams] = useSearchParams(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
참고ItemsPage 마켓 페이지의 로직들이 길게 나열되는 것이 지저분해 보여서 하나의 useItemPageState 커스텀 훅 통으로 로직을 분리해서 필요한 변수나 메서드를 반환하는 방식으로 처리를 했는데 더 나은 방향이 있을까요? 🥲
-> 지금도 나쁘지는 않지만, 하나의 훅이 너무 많은 일을 하고 있습니다! 하나의 훅이 여러 책임을 가지면 코드가 길어지고 유지보수가 어려워지며, 재사용성이 떨어집니다.
실무에서 생길 수 있는 시나리오를 예로 들면, 베스트 상품에 다른 정렬 옵션이 생기면 어떨까요? 이 훅은 더 커지고 서로 의존되지 않는 로직들이 뒤섞이게 되고 읽기는 더 힘들어질 거에요. 베스트 상품 영역이 커져도 훅에 묶여있으니 컴포넌트로 분리하기도 힘들겠죠!
저라면 훅을 쪼갤 거 같습니다.
const [pageSize] = usePageSize({
desktop: 10,
tablet: 6,
mobile: 4,
});
const [keyword, setKeyword] = useKeyword('');
const { items, loading, error } = useItems(keyword, pageSize);
대충 이런 느낌일 거 같아요. (수도 코드니 참고만 해주세요 🤣 )
</div> | ||
<BrowserRouter> | ||
<Routes> | ||
<Route element={<MainLayout header={<Header />} />}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
참고(App)MainLayout에서 header 컴포넌트를 주입받아 렌더링하도록 구현을 해보았습니다. 메인 페이지(/, Header)와 상품 페이지(/items, NavHeader)간의 헤더 형태의 차이가 있어서 주입 받도록 구현했는데 괜찮은 방식인지, 더 나은 방식도 있을 지 궁금합니다.
-> 좋습니다~! 👍 👍 재사용성이나 유지보수를 잘 고려하신 거 같아요!
@@ -0,0 +1,86 @@ | |||
import { useCallback, useMemo, useState } from "react"; | |||
|
|||
const useForm = ({ defaultValue = {}, resolver, mode = "onBlur" }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
참고(useForm), 참고(Validator)로그인/회원가입 페이지의 유효성 검사를 좀 더 재사용 가능하도록 만들기 위해서 react-hook-form을 사용해본 경험을 토대로 모방해서 Validator 클래스와 useForm 커스텀 훅을 구현해 적용해봤습니다! 하지만 페이지 최상단에서 커스텀 훅을 적용하다보니 유효성 검사를 위한 이벤트 발생 시에 페이지 전체가 리렌더링 되고 있습니다. useForm을 이용하면서 유효성 검사는 실제 필요한 부분만 리렌더링 되려면 어떻게 개선해 볼 수 있을까요? 🥲
->
우선, 리렌더링이 반드시 나쁜 것은 아닙니다. 🙂 필요할 때는 당연히 렌더링이 이루어져야 하죠!
그래도 렌더링을 줄이고 싶다면 필드별 상태 관리나 컴포넌트 범위 축소를 고려하거나, uncontrolled 방식으로 접근해볼 수 있을 것 같습니다.
(controlled, uncontrolled component를 키워드로 찾아보시면 이해에 도움이 될 거예요!)
다만, 원하시는 것처럼 uncontrolled 방식으로 세밀한 제어를 동시에 구현하는 것은 다소 어려울 수 있습니다.
이 때문에 react-hook-form이 많은 사랑을 받는 이유이기도 합니다. 😊
<BrowserRouter> | ||
<Routes> | ||
<Route element={<MainLayout header={<Header />} />}> | ||
<Route index path="/" element={<HomePage />} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
basic sprint 작업도 다 가져오셨군요! 😮 💯
return { status: result.status, ...data }; | ||
} catch (error) { | ||
console.error(error); | ||
return { status: 520, list: [], totalCount: 0 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
status code는 의미 있게 다루셔야 합니다~!
https://developer.mozilla.org/ko/docs/Web/HTTP/Status
또한 매번 try catch로 감싸면 오히려 에러 핸들링이 힘들어 질 수 있어요.
상단에서 ErrorBoundary를 쓰시거나, 아니면 실제로 에러 UI를 핸들링 할 수 있는 컴포넌트 단에서 try catch로 잡는 것도 좋습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오.. 깔끔하게 구조화 하셨네요! 👍
요구사항
기본
중고마켓
/items
입니다./items
일때 상단네비게이션바의 '중고마켓' 버튼의 색상은3692FF
입니다.https://panda-market-api.vercel.app/docs/#/
에 명세된GET
메소드/products
를 사용해주세요.상품 등록하기
버튼을 누르면/additem
로 이동합니다. ( 빈 페이지 )최신 순
또는좋아요 순
을 선택해서 정렬을 할 수 있습니다.중고마켓 반응형
체크리스트 [심화]
주요 변경사항
스크린샷
데스크탑

태블릿

모바일

멘토에게
ItemsPage
마켓 페이지의 로직들이 길게 나열되는 것이 지저분해 보여서 하나의useItemPageState
커스텀 훅 통으로 로직을 분리해서 필요한 변수나 메서드를 반환하는 방식으로 처리를 했는데 더 나은 방향이 있을까요? 🥲ItemsPage
)전체적으로 CSS module 을 활용해서 스타일링을 진행했습니다. 그런데ItemPage
컴포넌트에서 개별적으로 스타일을 적용하려다 보니 *클래스명에도 의미를 구체적으로 부여하는 것이 나은 지, 아니면 어차피 컴포넌트 별로 스코프가 나뉘어지니 간단하게 클래스명을 부여해도 될 지가 고민이 됩니다. 전자로 적용하자니 스타일을 적용하려는 요소들에 각각 클래스명을 부여하자니 클래스명을 매번 분리해서 작성하기도 번거롭고, 후자로 작성을 하자니 너무 간단한 클래스명으로 표현하려면 동일 컴포넌트 내 중복의 가능성이 높아져서요! 🤔 (ex:all_items_container
<->container
,search_button
<->button
)Select
)Select
컴포넌트에서Children
API를 활용하여children
prop으로 전달되는 요소들을Select
박스의 요소들로 나타나도록 한번 구현해보았습니다. 그런데 이렇게 구현하니Select
컴포넌트의children
props로 어떤 값을 전달해야 할 지 한 번에 알기 어렵고, 컴포넌트 내부 로직을 살펴보아야 알 수 있는 것 같아서 구현 후에나 고민이 되었습니다. 합성 컴포넌트 패턴을 사용하는 게 더 나은 방식일지 궁금합니다.Pagination
)Pagination
컴포넌트를 구현하다보니 내부 로직이 많이 복잡하게 구현이 된 것 같은 생각이 들었습니다 🥹.offset
방식으로 페이지네이션 구현 시, 본래 이렇게 복잡하게 구현되는 것이 맞는 지 궁금합니다.App
)MainLayout
에서header
컴포넌트를 주입받아 렌더링하도록 구현을 해보았습니다. 메인 페이지(/
,Header
)와 상품 페이지(/items
,NavHeader
)간의 헤더 형태의 차이가 있어서 주입 받도록 구현했는데 괜찮은 방식인지, 더 나은 방식도 있을 지 궁금합니다.useForm
), 참고(Validator
)로그인/회원가입 페이지의 유효성 검사를 좀 더 재사용 가능하도록 만들기 위해서react-hook-form
을 사용해본 경험을 토대로 모방해서Validator
클래스와useForm
커스텀 훅을 구현해 적용해봤습니다! 하지만 페이지 최상단에서 커스텀 훅을 적용하다보니 유효성 검사를 위한 이벤트 발생 시에 페이지 전체가 리렌더링 되고 있습니다.useForm
을 이용하면서 유효성 검사는 실제 필요한 부분만 리렌더링 되려면 어떻게 개선해 볼 수 있을까요? 🥲