-
Notifications
You must be signed in to change notification settings - Fork 21
[노현지] Sprint7 #69
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
The head ref may contain hidden characters: "React-\uB178\uD604\uC9C0-sprint7"
[노현지] Sprint7 #69
Conversation
…sed on the current path
스프리트 미션 하시느라 수고 많으셨어요. |
} | ||
|
||
export async function getItemComments(productId = "", { cursor = 0 }) { | ||
const query = `limit=${COMMENTS_LIMIT}&cursor=${cursor}`; |
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.
쿼리는 URLSearchParams
로 손쉽게 사용할 수 있어요 !
const query = `limit=${COMMENTS_LIMIT}&cursor=${cursor}`; | |
const query = new URLSearchParams({cursor, limit: COMMENTS_LIMIT, }); |
URLSearchParams
와 함께 객체로 손쉽게 핸들링할 수 있습니다 !
객체로 구성할 수 있어 가독성이 좋고, URL 인코딩을 자동으로 처리하여 특수 문자나 공백이 포함된 값에서도 안전하게 동작합니다 !
URLSearchParams:
URLSearchParams
인터페이스는 URL의 쿼리 문자열을 대상으로 작업할 수 있는 유틸리티 메서드를 정의합니다.
function PrimaryButton({ | ||
children, | ||
className = "", | ||
onClick = () => {}, | ||
disabled = false, | ||
}) { | ||
const buttonClass = `${styles.button} ${className}`; | ||
return ( | ||
<button className={buttonClass} onClick={onClick} disabled={disabled}> | ||
{children} | ||
</button> | ||
); | ||
} |
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.
(심화/제안/고민해보기) 혹시 버튼 컴포넌트들을 공통 버튼 컴포넌트로 리팩토링 할 수는 없을까요?
MenuButton
, DeleteButton
, PrimaryButton
.. 더 나아가서 SecondaryButton
, UpdateButton
등등 목적에 따라 버튼이 생겨날 수 있을 것 같아요.
만약 디자인 시스템이 바뀌어서 일괄적으로 버튼의 radius
를 바꿔야하는 상화이 온다면 유지보수하기가 어려워질 수 있겠지요?
예를 들어서 다음과 같은 컴포넌트를 만들어볼 수 있을 것 같아요:
import styles from "./Button.module.css";
function Button({
children,
variant = "primary",
icon,
// onClick = () => {},
className = "",
// disabled = false,
...rest
}) {
return (
<button
className={`${styles.button} ${styles[variant]} ${className}`}
// onClick={onClick}
// disabled={disabled} 해당 내용들은 `rest`에 자동 등재
{...rest}
>
{icon && <img src={icon} alt="" className={styles.icon} />}
{children}
</button>
);
}
export default Button;
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.
방금 제안드린 내용에서 추가
사실, 여기서 icon
또한 button
의 children
으로 포함시킬 수도 있긴 하겠네요 😊
예를 들어서 다음과 같이요 !:
<Button variant="error" className="flex justify-between w-24 items-center">삭제<DeleteIcon /></Button>
@@ -1,7 +1,7 @@ | |||
import { useState, useEffect } from "react"; | |||
import debounce from "lodash.debounce"; | |||
|
|||
function useWindowSize() { | |||
function useWindowSize(delay = 300) { |
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.
크으 ~ 피드백 반영 좋습니다 현지님 👍
<h2 className={styles.featureTag}>Search</h2> | ||
<h3 className={styles.bold}>구매를 원하는 상품을 검색하세요</h3> | ||
<p className={styles.featureDescription}> | ||
구매하고 싶은 물품은 검색해서 | ||
<br /> | ||
쉽게 찾아보세요 | ||
</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.
h
시리즈가 순차적으로 잘 들어갔네요 👍
<div className={`${styles.features} ${styles.wrapper}`}> | ||
<div className={styles.feature}> | ||
<img src={HomeImg1} width="68.5%" alt="인기 상품" /> | ||
<div className={styles.featureContent}> | ||
<h2 className={styles.featureTag}>Hot item</h2> | ||
<h3 className={styles.bold}>인기 상품을 확인해 보세요</h3> | ||
<p className={styles.featureDescription}> | ||
가장 HOT한 중고거래 물품을 | ||
<br /> | ||
판다 마켓에서 확인해 보세요 | ||
</p> | ||
</div> | ||
</div> |
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.
(제안/선택) section
을 사용하셔도 될 것 같아요.
<div className={`${styles.features} ${styles.wrapper}`}> | |
<div className={styles.feature}> | |
<img src={HomeImg1} width="68.5%" alt="인기 상품" /> | |
<div className={styles.featureContent}> | |
<h2 className={styles.featureTag}>Hot item</h2> | |
<h3 className={styles.bold}>인기 상품을 확인해 보세요</h3> | |
<p className={styles.featureDescription}> | |
가장 HOT한 중고거래 물품을 | |
<br /> | |
판다 마켓에서 확인해 보세요 | |
</p> | |
</div> | |
</div> | |
<section className={`${styles.features} ${styles.wrapper}`}> | |
<div className={styles.feature}> | |
<img src={HomeImg1} width="68.5%" alt="인기 상품" /> | |
<div className={styles.featureContent}> | |
<h2 className={styles.featureTag}>Hot item</h2> | |
<h3 className={styles.bold}>인기 상품을 확인해 보세요</h3> | |
<p className={styles.featureDescription}> | |
가장 HOT한 중고거래 물품을 | |
<br /> | |
판다 마켓에서 확인해 보세요 | |
</p> | |
</div> | |
</section> |
영역이 구분되며 h
로 각 섹션의 정체성이 명확하므로 section
태그도 괜찮은 의미일 것 같아서 제안드려요:
다음은 MDN의 <section>
에 대한 설명 중 첫 문장입니다.
The
<section>
HTML element represents a generic standalone section of a document, which doesn't have a more specific semantic element to represent it. Sections should always have a heading, with very few exceptions.
<section>
HTML 요소는 문서의 일반적인 독립형 섹션을 나타내며 이를 나타내는 더 구체적인 의미 요소가 없습니다. 섹션에는 거의 예외를 제외하고 항상 제목이 있어야 합니다.
function ItemCommentCard({ | ||
comment: { | ||
content, | ||
updatedAt, | ||
writer: { nickname, image }, | ||
}, | ||
}) { |
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.
크으 이렇게 props
를 받으니까 comment
가 어떤 구성으로 되어있는지 파악하기 좋네요 👍👍
{isEditMode ? ( | ||
<div className={styles.buttonContainer}> | ||
<button | ||
type="button" | ||
className={styles.cancelButton} | ||
onClick={handleEditCancel} | ||
> | ||
취소 | ||
</button> | ||
<PrimaryButton | ||
type="submit" | ||
className={styles.editCompleteButton} | ||
disabled={!editAvailable} | ||
onClick={handleEditComplete} | ||
> | ||
수정 완료 | ||
</PrimaryButton> | ||
</div> | ||
) : ( | ||
"" | ||
)} |
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.
다음과 같이 작성해볼 수 있습니다 !:
{isEditMode ? ( | |
<div className={styles.buttonContainer}> | |
<button | |
type="button" | |
className={styles.cancelButton} | |
onClick={handleEditCancel} | |
> | |
취소 | |
</button> | |
<PrimaryButton | |
type="submit" | |
className={styles.editCompleteButton} | |
disabled={!editAvailable} | |
onClick={handleEditComplete} | |
> | |
수정 완료 | |
</PrimaryButton> | |
</div> | |
) : ( | |
"" | |
)} | |
{isEditMode && ( | |
<div className={styles.buttonContainer}> | |
<button | |
type="button" | |
className={styles.cancelButton} | |
onClick={handleEditCancel} | |
> | |
취소 | |
</button> | |
<PrimaryButton | |
type="submit" | |
className={styles.editCompleteButton} | |
disabled={!editAvailable} | |
onClick={handleEditComplete} | |
> | |
수정 완료 | |
</PrimaryButton> | |
</div> | |
)} |
const handleLoad = async () => { | ||
try { | ||
const { list, nextCursor } = await getItemComments(productId, { | ||
cursor, | ||
}); | ||
setComments((prev) => [...prev, ...list]); | ||
setCursor(nextCursor); | ||
} catch (error) { | ||
alert(error.message); | ||
console.error("ERROR: ", error); | ||
} | ||
}; |
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.
해당 함수는 useCallback
을 사용해볼 수 있습니다 !:
const handleLoad = useCallback(async () => {
try {
const { list, nextCursor } = await getItemComments(productId, { cursor });
setComments((prev) => [...prev, ...list]);
setCursor(nextCursor);
} catch (error) {
alert(error.message);
console.error("ERROR: ", error);
}
}, [productId, cursor]); // ✅ 의존성 추가
수고하셨습니다 현지님 ! 미션 수행하시느라 수고 많으셨습니다 현지님 ! 😊👍 |
요구사항
기본
상품 상세
상품 문의 댓글
심화
주요 변경사항
handleLoad
함수를useEffect
안에 선언alt=""
로 수정handleLoad
함수를useEffect
안에 선언alt=""
로 수정alt=""
로 수정멘토에게