Skip to content
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

[홍재원] week20 #563

Conversation

hongjw030
Copy link
Collaborator

@hongjw030 hongjw030 commented Jan 21, 2024

요구사항

기본

  • [기본] 프로젝트 전반에 필요한 리팩토링, 기능 개선을 진행했나요?
  • [기본] 즐겨찾기 설정된 카드의 별은 파랑색이 되나요?
  • [기본] 파랑색 별을 다시 클릭하면 즐겨찾기 설정이 해제되고 회색으로 돌아가나요?
  • [기본] 즐겨찾기 설정/해제는 PUT ‘/links/{linkId}’ 를 활용했나요?

심화

  • [심화] 카드를 클릭하고 드래그 해서 원하는 위치로 이동하면 순서가 바뀌는 2차원 드래그 앤 드롭 기능을 만들었나요?

주요 변경사항

  • 전체적으로 리팩토링 진행했습니다.

스크린샷

image

멘토에게

  • 왜인지는 모르겠지만.... put/links/{linkId} 로 request 보내도 성공하질 않습니다 ㅠㅠ 아무리 시도해도 400 에러만 뜨는데 왜인지를 모르겠습니다.
  • 가끔 뜬금없이 useQuery 캐시가 제대로 저장되지 않는 문제가 있습니다. 항상 발생하는 버그가 아니라 가끔 랜덤하게 발생하는데, 이유를 모르겠습니다... 아래 gif 첨부했습니다!
  • 셀프 코드 리뷰를 통해 질문 이어가겠습니다.

Honeycam 2024-01-21 23-40-02

@hongjw030 hongjw030 added 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. 미완성 죄송합니다.. labels Jan 21, 2024
@@ -1,26 +1,57 @@
/*Card 컴포넌트*/

import Link from "next/link";
import { useDrag, useDrop } from "react-dnd";
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

react dnd 라이브러리 사용했습니다!!
react beautiful dnd보다 용량도 작고 다운로드 횟수가 많아서 선택했는데, 나중에 시간 되면 라이브러리 없이 직접 dnd 구현해보겠습니당..!!

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 +20 to +27
const { mutate } = useMutation({
onMutate: () => setFakeFilled(!fakeFilled),
mutationFn: () => updateCardFavorite(cardId, !isFilled),
onSettled: () => {
setFakeFilled(isFilled);
queryClient.invalidateQueries({ queryKey: ["card-list"] });
},
});
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

옵티미스틱 업데이트를 써보려고 state를 추가해서 썼습니다!!
저 근데... ㅠㅠ 이상하게 updateCardFavorite api가 먹히질 않습니다, 에러 메세지는 다음과 같습니당.

카드의 별모양 버튼을 눌러 put links/id 요청을 보내면 아래와 같은 에러 메세지가 뜹니다.

image

근데 스웨거에서 직접 로그인하고 시도해도 똑같은 에러가 납니다.. ㅠㅠ
image

Copy link
Collaborator

Choose a reason for hiding this comment

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

일단 메세지가 보아하니.. 쿼리 머시기머시기 적혀있어서 파라미터가 정확하다면 백엔드 이슈 혹은 백엔드 분에게 물어봐야할 것 같아요ㅠㅜ

스크린샷 2024-01-23 오전 3 01 54

지금은 되는 것 같은데 맞을까요??

Comment on lines 27 to +39
return (
<div className={styles["dropdown"]}>
<button onClick={handleLogout}>로그아웃</button>
<Link href="/folders">전체</Link>
{folderList.map((folder) => {
if ("id" in folder) {
return (
<Link href={`/folders/${folder.id}`} key={folder.id}>
{folder.name}
</Link>
);
}
})}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

로그인된 경우 Nav 컴포넌트의 프로필 영역을 누르면

  1. 로그아웃
  2. 전체 폴더 페이지로 이동
  3. 그외 폴더들 페이지로 이동
    할 수 있는 드롭다운입니당.

Comment on lines 31 to +47

useLayoutEffect(() => {
if (typeof folderId !== "string" && typeof folderId !== "undefined") {
router.replace("/folders");
useToast(false, "잘못된 경로입니다!");
}
// BUG - 일정 시간이 지난 후에야 redirect 되는 문제 발생
if (isError) {
router.replace("/folders");
useToast(false, "존재하지 않는 폴더입니다!");
}
}, [folderId, router, isError]);

if (typeof folderId !== "string") {
return null;
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

제 의도: 만약 useQuery가 isError 상태라면, (존재하지 않는 folderId를 받은 경우라면) 잘못된 경로라는 토스트 메세지가 뜨면서 /folders 페이지로 이동하게 하려고 했습니다. 그리고 CSR에서 리다이렉트가 일어나니 페이지 노출을 없애려고 useEffectLayout을 사용했습니다.

실제 상황: isError 값이 나오기까지 한 5초 정도 folders/folderId 페이지에 머무르다가 isError 값이 나오면 그제야 /folders 페이지로 이동됩니다. 어떻게 하면 잘못된 페이지 노출 없이, CSR 환경에서 페이지 리다이렉팅을 할 수 있을까요?
그리고 잘못된 페이지 노출을 막기 위해 useLayoutEffect를 썼는데 전혀 문제가 고쳐지지 않았습니다. 왜 그런건지 이유를 모르겠습니다...!!

Copy link
Collaborator

Choose a reason for hiding this comment

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

저는 useEffect는 css를 입히고 시작하므로 맨 처음 setState시 깜빡임을 개선하기 위해 useLayoutEffect를 쓰면 css 입히기 전에 동작한다고 알고 있어용
그래서 현 상황은 네트워크 통신이 완료 되어야 결과를 알 수 있는거라서 useLayoutEffect는 솔루션이 아니겠다는 생각이구용.

  1. 먼저 페이지 이동을 함 -> 2. 네트워크 통신을 함 -> 3. 기다림 -> 4. 결과를 알게됨(isError)
    이미 2번 단계 진입 시 useLayoutEffect의 효능은 끝났다고 알고있습니다

따라서,
5초나 걸리는지는 모르겠지만 결과적으로 데이터 로딩 중에 페이지가 보이는 일을 방지하는게 목적이라면
CSR에서 많이 쓰이는 방법으로는 로딩, 스켈레톤, if(!data) return <></> 등이 있을 것 같네요
어쩔 수 없이 html 문서를 받아야하고, 랜더도 해야하고, useEffect가 돌아야 데이터 통신을 하고 그래야만 isError가 존재하는지 아닌지 알 수 있어서 그래요
react-query는 내부적으로

const useQuery = () => {
//...
  useEffect(()=>{
  queryFn();
},[])
//...
}

이렇게 생겼다고 상상하시면 좋을 것 같습니다!
즉, 페이지에 진입을 해야만 결과를 알 수 있는 것이죠...

getServerSideProps에서 관련 로직을 관리한다면 한템포 빨라질 것 같습니다만 페이지 전환 시에는 모호하네요.

따라서 로딩, 스켈레톤,if방어코드 등으로 우회할 수밖에 없을 것 같아요 ㅜㅠ

정말 더 개선 한다면 페이지 이동 전에 네트워크 통신을 하고 성공 시에만 페이지 전환을 하는 방법도 있지만, 존재하지 않는 id가 리스트업 되어있는게 잘못된 상황이라 이런 경우는 거의 없을 것 같아요...!

Copy link
Collaborator

Choose a reason for hiding this comment

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

isloading, isfetch도 적절히 고려하면 좋을 것 같습니다(다른 상황에서)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

이부분~!!!! 너무너무 꿀팁 꿀정보라 코멘트 꼭 남겨야지 하다가 시간을 넘겨버렸네요, 넘 죄송하고 피드백 너무너무 감사합니다...!!! 덕분에 저도 여러모로 배워갑니다.

그럼 우선 이 부분은 스켈레톤 ui를 만들어볼까 싶어용. 말씀대로 폴더id를 미리 리스트업해두는건 맞지 않으니 다른 식으로 우회해야 할 거 같네요. 좋은 방법 알려주셔서 넘 감사합니다!!!!

@hongjw030 hongjw030 requested a review from yusunghyun January 21, 2024 14:37
Copy link
Collaborator

@yusunghyun yusunghyun left a comment

Choose a reason for hiding this comment

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

안녕하세요 재원님 처음 코드리뷰를 하게 되었네요 반갑습니다 👍

일단 캐시 날아가는 이슈는 처음 보고 저도 깜짝 놀랐는데 솔루션은
_app.tsx에서 queryClient를 컴포넌트 외부에서 선언하면 해결이 됩니다 ㅎㅎ
이게 컴포넌트 밖에 있으면 '한번'만 선언되고 쭉 유지가 되는데 컴포넌트 내부에 있으면 여러가지 요인으로 재선언 되는데 그러면 객체가 새거가 되어서 캐시가 날아가는 이슈가 있어요!
React-query에서 뿐만 아니라 이러한 이슈 때문에 useMemo, useCallback 등이 사용된답니다!

전반적으로 코드 정리가 아주 잘되어있네요 재사용도 적재적소되어있고 파일도 분리가 잘 되어있고 불필요한 코드가 거의 없는 것 같아요 컴포넌트도 잘 운용하셔서 굳이 다음 챌린지가 있다면 mui처럼 같은 만능 공용 모듈� 관련하여 알아보면 도움이 되실거라 생각합니다!

적어도 컴포넌트의 사용, 훅의 사용 측면에서는 지금까지 본 코드 중에서 가장 잘 사용하셨다고 생각합니다 재원님의 방식을 주변 분들에게 널리 알려주셔도 좋을 것 같아요!

위클리 하시느라 고생 많으셨고 프로젝트에 재원님이 좋은 기여를 해주실 것 같아 든든한 생각이 듭니다!
궁금한점 대댓글(태그꼭), DM, 궁금궁금 편하게 남겨주세요! 이번 주도 화이팅입니다~!~!

@@ -1,11 +1,13 @@
import { UserType } from "@/types/UserType";
import { axiosInstance } from "./axiosInstance";

// 로그인된 유저의 정보를 조회하는 api
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 31 to +47

useLayoutEffect(() => {
if (typeof folderId !== "string" && typeof folderId !== "undefined") {
router.replace("/folders");
useToast(false, "잘못된 경로입니다!");
}
// BUG - 일정 시간이 지난 후에야 redirect 되는 문제 발생
if (isError) {
router.replace("/folders");
useToast(false, "존재하지 않는 폴더입니다!");
}
}, [folderId, router, isError]);

if (typeof folderId !== "string") {
return null;
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

저는 useEffect는 css를 입히고 시작하므로 맨 처음 setState시 깜빡임을 개선하기 위해 useLayoutEffect를 쓰면 css 입히기 전에 동작한다고 알고 있어용
그래서 현 상황은 네트워크 통신이 완료 되어야 결과를 알 수 있는거라서 useLayoutEffect는 솔루션이 아니겠다는 생각이구용.

  1. 먼저 페이지 이동을 함 -> 2. 네트워크 통신을 함 -> 3. 기다림 -> 4. 결과를 알게됨(isError)
    이미 2번 단계 진입 시 useLayoutEffect의 효능은 끝났다고 알고있습니다

따라서,
5초나 걸리는지는 모르겠지만 결과적으로 데이터 로딩 중에 페이지가 보이는 일을 방지하는게 목적이라면
CSR에서 많이 쓰이는 방법으로는 로딩, 스켈레톤, if(!data) return <></> 등이 있을 것 같네요
어쩔 수 없이 html 문서를 받아야하고, 랜더도 해야하고, useEffect가 돌아야 데이터 통신을 하고 그래야만 isError가 존재하는지 아닌지 알 수 있어서 그래요
react-query는 내부적으로

const useQuery = () => {
//...
  useEffect(()=>{
  queryFn();
},[])
//...
}

이렇게 생겼다고 상상하시면 좋을 것 같습니다!
즉, 페이지에 진입을 해야만 결과를 알 수 있는 것이죠...

getServerSideProps에서 관련 로직을 관리한다면 한템포 빨라질 것 같습니다만 페이지 전환 시에는 모호하네요.

따라서 로딩, 스켈레톤,if방어코드 등으로 우회할 수밖에 없을 것 같아요 ㅜㅠ

정말 더 개선 한다면 페이지 이동 전에 네트워크 통신을 하고 성공 시에만 페이지 전환을 하는 방법도 있지만, 존재하지 않는 id가 리스트업 되어있는게 잘못된 상황이라 이런 경우는 거의 없을 것 같아요...!

Comment on lines +66 to +70
<DndProvider backend={HTML5Backend}>
<div className={styles["card-list-section"]}>
<CardListWrapper folderId={folderId} keyword={keyword} />
</div>
</DndProvider>
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 +1 to +2
/* 회원가입 페이지 */

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 31 to +47

useLayoutEffect(() => {
if (typeof folderId !== "string" && typeof folderId !== "undefined") {
router.replace("/folders");
useToast(false, "잘못된 경로입니다!");
}
// BUG - 일정 시간이 지난 후에야 redirect 되는 문제 발생
if (isError) {
router.replace("/folders");
useToast(false, "존재하지 않는 폴더입니다!");
}
}, [folderId, router, isError]);

if (typeof folderId !== "string") {
return null;
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

isloading, isfetch도 적절히 고려하면 좋을 것 같습니다(다른 상황에서)

const handleCloseDropdown = () => {
setTimeout(() => setIsOpen(false), 200);
};
const { isOpen, handleOpen, handleClose } = useDropdown();
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 +20 to +27
const { mutate } = useMutation({
onMutate: () => setFakeFilled(!fakeFilled),
mutationFn: () => updateCardFavorite(cardId, !isFilled),
onSettled: () => {
setFakeFilled(isFilled);
queryClient.invalidateQueries({ queryKey: ["card-list"] });
},
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

일단 메세지가 보아하니.. 쿼리 머시기머시기 적혀있어서 파라미터가 정확하다면 백엔드 이슈 혹은 백엔드 분에게 물어봐야할 것 같아요ㅠㅜ

스크린샷 2024-01-23 오전 3 01 54

지금은 되는 것 같은데 맞을까요??

@@ -1,26 +1,57 @@
/*Card 컴포넌트*/

import Link from "next/link";
import { useDrag, useDrop } from "react-dnd";
Copy link
Collaborator

Choose a reason for hiding this comment

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

신기하고 간결한 라이브러리네요!

@yusunghyun
Copy link
Collaborator

머지하겠습니다!

@yusunghyun yusunghyun merged commit e8c93de into codeit-bootcamp-frontend:part3-홍재원 Jan 25, 2024
@hongjw030
Copy link
Collaborator Author

@yusunghyun
우선~ 피드백 넘 감사드립니다 멘토님!!!!
아직 부족한 점 많은 플젝인데 여러모로 피드백 남겨주셔서 감사해요.
특히 useLayoutEffect 부분에서 혼자 감탄 연발하고 난리도 아녔다네영... ㅋㅋㅋ 이런 거 보면 그냥 ㅁㅁ훅은 뭐시기 기능을 한다~ 라고만 외워쓰는 게 잘못된 공부방식인 거 같아요. 오늘 멘토링에서 미들웨어 얘기하신 것도 그렇고 정확히 어떤 순서에 따라 동작하는지 정확히 파악하는 게 중요한...

멘토님 피드백대로 한 번 다시 플젝 리팩토링 해보겠습니다, 늘 감사합니다!!!

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