Skip to content

Conversation

@rak517
Copy link
Collaborator

@rak517 rak517 commented Jan 4, 2025

요구사항

기본

  • 스프린트 미션 1 ~ 7에 대해 typescript를 적용해주세요

심화

  • any타입을 최소한으로 써주세요

주요 변경사항

  • js 에서 tsx 마이그레이션
  • 라우팅 설정 변경
  • product 도메인 로직 분리

멘토에게

  • 아직 타입스크립트를 활용을 잘 못해서 그런지 지금까지의 스프린트 미션에 적용을 해봤지만 정적 타입 검사로 인한 이점이나 OOP 개념을 잘 적용 시키지 못하겠습니다. 어떻게해야 타입스크립트 활용함으로써 타입스크립트의 주요 이점들을 가져올 수 있을까요?
  • 이런식으로 사용하는 건지도 잘 모르겠습니다 ㅜㅜ
  • apiRequest → handleResponseError → HttpException로 이어지는 API~UI 레이어까지 한 흐름으로 자연스럽게 이어지는 에러 전파를 구현해보려고 노력해봤는데 이렇게 해뒀다면 사용하는 UI 컴포넌트나 호출부 에서는 일관되게 catch에서 setError(error.message) 정도만 처리해도 충분할까요?
  • itemPage에서 반응형에 따라 pageLimit로 reSize를 정하는데 onResizeEvent가 와르르 발생할 때에 대한 퍼포먼스 핸들링을 위해 debounce를 적용시켜 봤는데 실제로 이 delay = 300은 서버에 부담을 많이 줄여주나요?

@rak517 rak517 self-assigned this Jan 4, 2025
@rak517 rak517 added the 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. label Jan 4, 2025
@rak517 rak517 requested a review from Lanace January 4, 2025 14:43
@rak517 rak517 removed their assignment Jan 6, 2025
@rak517 rak517 requested review from Lanace and removed request for Lanace January 8, 2025 12:48
@rak517 rak517 assigned Lanace and unassigned Lanace Jan 12, 2025
Copy link
Collaborator

@Lanace Lanace left a comment

Choose a reason for hiding this comment

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

개발하시느라 고생 많으셨어요ㅎㅎ!

Comment on lines +19 to +28
const getProducts = async (limit: number, sort: SortOption): Promise<void> => {
try {
const { list } = await fetchProducts(sort, limit);
setItems(list);
} catch (error) {
console.error(error);
const message = error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다";
setError(message);
}
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

이정도로 예외처리 해도 충분하긴 해요!

아마 느끼셨겠지만 이런 부분들이 매우 많이 사용될꺼에요.
그래서 이걸 추상화하고 공통으로 묶어서 사용하려고 사람들이 많이 시도해왔는데, react-query라는 라이브러리를 한번 사용해보시면 좋을것같아요ㅎㅎ!

이거 같이 멘토링에서 해보시져...!

Comment on lines +37 to +41
useEffect(() => {
const debounceResize = debounce(handleResize, 300);
window.addEventListener("resize", debounceResize);
return () => window.removeEventListener("resize", debounceResize);
}, [handleResize]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

resize 될때 처리한 부분도 나쁘지 않게 잘 된것같아요ㅎㅎ!
이부분떄문에 서버에 성능부하를 주진 않을꺼에요~

왜냐하면 값이 바뀌었을때만 요청이 날아갈꺼거든요!

Comment on lines +54 to +60
<section className="all-products">
<div className="all-products-list">
{items.map((item) => (
<ItemCard key={item.id} item={item} />
))}
</div>
</section>
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 +15 to +26
const getProducts = async (limit: number): Promise<void> => {
if (limit !== null) {
try {
const { list } = await fetchProducts("favorite", limit);
setItems(list);
} catch (error) {
console.error(error);
const message = error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다";
setError(message);
}
}
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

전반적으로 비슷한 코드 스타일로 통일되어있네요

매우 좋은 습관이에요
코드의 스타일이 일관되어야 읽기도 좋고 나중에 문제가 생겨도 찾기가 좋거든요ㅎㅎ!

Copy link
Collaborator

Choose a reason for hiding this comment

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

다만 거의 비슷한 코드가 계속해서 나오는건 공통화 시킬 수 있다는거니 개선해볼 수 있을것같아요ㅎㅎ!

}, [handleResize]);

useEffect(() => {
if (typeof pageSize === "number") {
Copy link
Collaborator

Choose a reason for hiding this comment

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

pageSize 값이 number가 아닌 다른값이 나올떄도 있나요??

Comment on lines +8 to +13
interface CommentListProps {
comments: Comment[];
}

function CommentList({ comments }: CommentListProps) {
const getRelativeTime = (createdAt: string, updatedAt: string) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Props 타입 잘 정의하셨는데요?ㅋㅋ

깔끔하게 필요한 props만 정의해서 사용했네여

const [inputValue, setInputValue] = useState<string>("");

const handleInputChange = (e) => {
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>): void => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

input 이랑 textarea랑 같이 사용하려고 하신 이유가 있을까요?

Comment on lines +6 to +10
interface ImageUploadProps {
title: string;
}

function ImageUpload({ title }: ImageUploadProps) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

이 컴포넌트도 잘 작성해주신것같아요

이미지 업로드를 하려고 하면 URL.revokeObjectURL 로 미리보기를 보여주려고 하신거가 좋네여

근데 스웨거에 보면 https://panda-market-api.vercel.app/docs/#/Image/ImageUpload 가 있어서
이미지를 업로드하면 url이 응답값으로 오는걸 볼 수 있을거에요

그래서 차라리 image 를 업로드하고 결과값으로 오는 url을 화면에 보여주는게 좀더 좋을것같아요ㅎㅎ!

Comment on lines +4 to +21
export async function apiRequest<T>(url: string, options?: RequestInit): Promise<T> {
try {
const response = await fetch(url, {
headers: { "Content-Type": "application/json" },
...options,
});
if (!response.ok) {
handleResponseError(response);
}
return await response.json();
} catch (error) {
if (error instanceof HttpException) {
throw error;
}
console.error("네트워크 오류", error);
throw new Error("네트워크 오류가 발생했습니다. 잠시 후 다시 시도해주세요.");
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

이거는 예전부터 사용해오시던건가여??

잘 작성하셨길래...ㅎㅎ;;

좀더 개선해보자면 Promise reject으로 error 를 throw해주면 좀더 좋을것같아요ㅎㅎ!

Comment on lines +1 to +12
export function debounce<T extends (...args: any[]) => void>(callback: T, delay = 300) {
let timeoutId: ReturnType<typeof setTimeout> | null = null;

return (...args: Parameters<T>) => {
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
callback(...args);
}, delay);
};
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

이건 직접 작성하신건가여??

lodash를 사용해보시는것도 좋을것같아요ㅎㅎ!

@Lanace
Copy link
Collaborator

Lanace commented Jan 14, 2025

타입스크립트 관련해서는 너무 처음부터 잘 쓰려고 생각하시는것보단 그냥 다른 라이브러리나 다른사람이 작성해둔 코드를 사용해보다보면 어떤게 편하고 어떤게 불편하다는게 느낌이 올꺼에요ㅎㅎ!

특히 서버랑 통신하는 부분을 보면 어떻게 response가 올지 모르는 any로 반환하는 함수와 타입이 명시되어있는 api는 개발자한테 개발경험이 매우 다르거든요ㅎㅎ;;

그래서 한번 멘토링에서 같이 보면 좋을것같아요!
이건 다들 중요한 내용들이라

@Lanace
Copy link
Collaborator

Lanace commented Jan 14, 2025

itemPage에서 반응형에 따라 pageLimit로 reSize를 정하는데 onResizeEvent가 와르르 발생할 때에 대한 퍼포먼스 핸들링을 위해 debounce를 적용시켜 봤는데 실제로 이 delay = 300은 서버에 부담을 많이 줄여주나요?

이거 관련해서는 딱히 debounce를 사용하지 않았어도 괜찮았을것같아요
왜냐하면 pageSize가 바뀌었을때만 request를 보내도록 하면 되거든요ㅎㅎ!

@Lanace Lanace merged commit 7fbd1ee into codeit-bootcamp-frontend:React-최성락 Jan 14, 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.

3 participants