-
Notifications
You must be signed in to change notification settings - Fork 26
[정상인] sprint5 #95
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
[정상인] sprint5 #95
The head ref may contain hidden characters: "React-\uC815\uC0C1\uC778-sprint5"
Conversation
|
스프리트 미션 하시느라 수고 많으셨어요. |
세팅에 문제가 있어서 rebase를 했더니 이전 커밋들이 남아있네욥...하핳 괜찮습니다 ! |
| html, | ||
| body { | ||
| padding: 0; | ||
| margin: 0; | ||
| } | ||
| .logo.react:hover { | ||
| filter: drop-shadow(0 0 2em #61dafbaa); | ||
|
|
||
| ul, | ||
| li { | ||
| list-style: none; | ||
| margin: 0; | ||
| padding: 0; | ||
| } | ||
|
|
||
| @keyframes logo-spin { | ||
| from { | ||
| transform: rotate(0deg); | ||
| } | ||
| to { | ||
| transform: rotate(360deg); | ||
| } | ||
| a { | ||
| text-decoration: none; | ||
| color: black; | ||
| } | ||
|
|
||
| @media (prefers-reduced-motion: no-preference) { | ||
| a:nth-of-type(2) .logo { | ||
| animation: logo-spin infinite 20s linear; | ||
| } | ||
| p { | ||
| margin: 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.
(제안/선택) 기본 스타일을 초기화하고 싶다면 reset.css도 좋은 방법이 될 수 있어요 ! 😊
브라우저마다 기본 스타일이 미묘하게 다른거 알고 계셨나요?
https://stackoverflow.com/questions/11578819/css-reset-what-exactly-does-it-do
이처럼 브라우저마다 스타일이 다른 경우 일관된 스타일을 제공할 수 있도록 reset.css를 작성하기도 한답니다 !
그대로 사용하셔도 좋고, 참고해도 좋은 Eric meyer의 reset.css는 다음과 같습니다:
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}| <Routes> | ||
| {/* 처음 시작 시 /items 로 이동 */} | ||
| <Route path="/" element={<Navigate to="/items" />} /> | ||
|
|
||
| <Route element={<Layout />}> | ||
| <Route path="/items" element={<ItemsPage />} /> | ||
| <Route path="/addItem" element={<AddItemPage />} /> | ||
| {/* freeBoard : link active 테스트를 위해 미리 만듦 */} | ||
| <Route path="/freeBoard" element={<FreeBoard />} />{" "} | ||
| </Route> | ||
| </Routes> |
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.
굿굿 ! react-router를 적절히 사용하셨군요 !
훌륭합니다. 레이아웃을 래핑하신거 보니 라이브러리 사용 방법도 꼼꼼히 확인하고 적용하신 것 같네요 👍
| const DropDown = ({ children }) => { | ||
| return <div className="dropdown">{children}</div>; | ||
| }; | ||
|
|
||
| DropDown.header = ({ children, onClick }) => { | ||
| return ( | ||
| <button onClick={onClick} className="button dropdown-btn"> | ||
| {children} | ||
| </button> | ||
| ); | ||
| }; | ||
|
|
||
| DropDown.menus = ({ children, isOpen }) => { | ||
| return isOpen && <ul className="dropdown-menus">{children}</ul>; | ||
| }; |
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.
크으 ~ 역시 👍👍👍
확장성과 유연성을 확보하셨군요 👍👍 각 컴포넌트가 기능 별로 확실히 구분되어 좋습니다 !
학습을 위해 컴포넌트를 구조적으로 설계하시려는 시도가 특히 좋네요 ! 멋집니다 !
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.
(생각해보기/인사이트) 컴포넌트를 최소한의 단위로 잘게 쪼개는게 긍정적인 면만 있을까?
다음 코드를 볼게요 !
<DropDown>
<DropDown.header onClick={handleClick}>메뉴</DropDown.header>
<DropDown.menus isOpen={isOpen}> ... </DropDown.menus>
</DropDown>현재는 위와 같이 사용해야 할거예요.
다음 코드처럼 단순하게 만들어 볼 수도 있을거예요:
const DropDown = ({ label, isOpen, onToggle, children }) => {
return (
<div className="dropdown">
<button onClick={onToggle} className="button dropdown-btn">
{label}
</button>
{isOpen && <ul className="dropdown-menus">{children}</ul>}
</div>
);
};만약 위처럼 만든다면 다음과 같이 사용해볼 수 있어요:
<DropDown
label="메뉴 열기"
isOpen={isOpen}
onToggle={() => setIsOpen((prev) => !prev)}
>
<li>항목 1</li>
<li>항목 2</li>
</DropDown>상인님이 보기에는 어떤게 더 심플하게 사용할 수 있다고 느껴지시나요? 😊
참고로 "이게 더 옳다"를 말하는게 아닙니다 ! 상인님께서 작성하신 코드는 확장성과 유연성 측면에서는 우위를 가진다고 사료되며, 다른 시각도 생각해보실 수 있을 것 같아서 코멘트 드립니다 😉😉
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.
(심화) 또한, 컴포넌트 컴파운드 패턴을 적용하실 수도 있을거예요.
현재 목적 별로 잘 구성해놓으셨기에 Component Compound 패턴으로 리팩토링하시기 쉬어보여서 제안드려봅니다 !
| const DropDown = ({ children }) => { | |
| return <div className="dropdown">{children}</div>; | |
| }; | |
| DropDown.header = ({ children, onClick }) => { | |
| return ( | |
| <button onClick={onClick} className="button dropdown-btn"> | |
| {children} | |
| </button> | |
| ); | |
| }; | |
| DropDown.menus = ({ children, isOpen }) => { | |
| return isOpen && <ul className="dropdown-menus">{children}</ul>; | |
| }; | |
| const DropDownContext = createContext(); | |
| export const DropDown = ({ children }) => { | |
| const [isOpen, setIsOpen] = useState(false); | |
| return ( | |
| <DropDownContext.Provider value={{ isOpen, setIsOpen }}> | |
| <div className="dropdown">{children}</div> | |
| </DropDownContext.Provider> | |
| ); | |
| }; | |
| DropDown.Header = ({ children }) => { | |
| const { setIsOpen } = useContext(DropDownContext); | |
| return ( | |
| <button onClick={() => setIsOpen((prev) => !prev)} className="button dropdown-btn"> | |
| {children} | |
| </button> | |
| ); | |
| }; | |
| DropDown.Menu = ({ children }) => { | |
| const { isOpen } = useContext(DropDownContext); | |
| return isOpen && <ul className="dropdown-menus">{children}</ul>; | |
| }; |
이미 리액트를 경험해보셨기에 조금 심화 피드백을 드려봅니다 !
위와 같이 구성한다면 상태를 자식 컴포넌트 간에 공유할 수 있어서 있어서 "Dropdown" 내에서 생태계가 이뤄질 수 있습니다. 😊😊
| const navLinks = [ | ||
| { _id: 1, title: "자유게시판", url: "/freeBoard" }, | ||
| { _id: 2, title: "중고마켓", url: "/items" }, | ||
| ]; |
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 isMobile = useMediaQuery({ maxWidth: 767 }); | ||
|
|
||
| if (isMobile) { | ||
| return [1, 4]; // [베스트상품 pageSize, 전체상품 pageSize] |
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 [1, 4]; // [베스트상품 pageSize, 전체상품 pageSize] | |
| return { | |
| bestProductPageSize: 1, | |
| productPageSize: 4, | |
| }; |
| try { | ||
| const { data } = await instance.get("/products", { params }); | ||
| console.log(data); | ||
| return [data.list, data.totalCount]; |
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 [data.list, data.totalCount]; | |
| return data; |
배열로 전달되면 첫번째, 두번째 요소를 파악하기 위해 해당 코드까지 확인해서 유추해야할거예요 !
| @@ -0,0 +1,11 @@ | |||
| import { instance } from "../utils/api"; | |||
|
|
|||
| export const useGetProduct = async (params) => { | |||
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.
해당 함수는 어떠한 상태도 가지지 않고 있네요 !
즉. 리액트 라이브러리를 사용하지 않는 모듈로 보여요.
use~로 작성하시면 자칫 훅으로 오해할 수 있으므로 다음과 같이 작성해볼 수 있을거예요:
| export const useGetProduct = async (params) => { | |
| export const getProduct = async (params) => { |
| @@ -0,0 +1,11 @@ | |||
| import { instance } from "../utils/api"; | |||
|
|
|||
| export const useGetProduct = async (params) => { | |||
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.
또한, params를 읽었을 때 "어떤 값"이 필요한지 알기 어려울 수 있어요.
| export const useGetProduct = async (params) => { | |
| export const useGetProduct = async ({ page, pageSize, orderBy }) => { |
위와 같이 작성해준다면 "어떤 파라메터"가 필요한지 명확해지겠죠? 😉
|
훌륭합니다 상인님 ! 이번 미션 정말 수고 많으셨습니다 😉😉 |
요구사항
기본
중고마켓
배포링크
중고마켓 반응형
베스트 상품
전체 상품
심화
스크린샷
멘토에게