-
Notifications
You must be signed in to change notification settings - Fork 51
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
The head ref may contain hidden characters: "part3-\uD64D\uC7AC\uC6D0-week20"
[홍재원] week20 #563
Conversation
@@ -1,26 +1,57 @@ | |||
/*Card 컴포넌트*/ | |||
|
|||
import Link from "next/link"; | |||
import { useDrag, useDrop } from "react-dnd"; |
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 dnd 라이브러리 사용했습니다!!
react beautiful dnd보다 용량도 작고 다운로드 횟수가 많아서 선택했는데, 나중에 시간 되면 라이브러리 없이 직접 dnd 구현해보겠습니당..!!
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 { mutate } = useMutation({ | ||
onMutate: () => setFakeFilled(!fakeFilled), | ||
mutationFn: () => updateCardFavorite(cardId, !isFilled), | ||
onSettled: () => { | ||
setFakeFilled(isFilled); | ||
queryClient.invalidateQueries({ queryKey: ["card-list"] }); | ||
}, | ||
}); |
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.
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> | ||
); | ||
} | ||
})} |
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.
로그인된 경우 Nav 컴포넌트의 프로필 영역을 누르면
- 로그아웃
- 전체 폴더 페이지로 이동
- 그외 폴더들 페이지로 이동
할 수 있는 드롭다운입니당.
|
||
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; | ||
} | ||
|
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.
제 의도: 만약 useQuery가 isError 상태라면, (존재하지 않는 folderId를 받은 경우라면) 잘못된 경로라는 토스트 메세지가 뜨면서 /folders 페이지로 이동하게 하려고 했습니다. 그리고 CSR에서 리다이렉트가 일어나니 페이지 노출을 없애려고 useEffectLayout을 사용했습니다.
실제 상황: isError 값이 나오기까지 한 5초 정도 folders/folderId 페이지에 머무르다가 isError 값이 나오면 그제야 /folders 페이지로 이동됩니다. 어떻게 하면 잘못된 페이지 노출 없이, CSR 환경에서 페이지 리다이렉팅을 할 수 있을까요?
그리고 잘못된 페이지 노출을 막기 위해 useLayoutEffect를 썼는데 전혀 문제가 고쳐지지 않았습니다. 왜 그런건지 이유를 모르겠습니다...!!
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.
저는 useEffect는 css를 입히고 시작하므로 맨 처음 setState시 깜빡임을 개선하기 위해 useLayoutEffect를 쓰면 css 입히기 전에 동작한다고 알고 있어용
그래서 현 상황은 네트워크 통신이 완료 되어야 결과를 알 수 있는거라서 useLayoutEffect는 솔루션이 아니겠다는 생각이구용.
- 먼저 페이지 이동을 함 -> 2. 네트워크 통신을 함 -> 3. 기다림 -> 4. 결과를 알게됨(isError)
이미 2번 단계 진입 시 useLayoutEffect의 효능은 끝났다고 알고있습니다
따라서,
5초나 걸리는지는 모르겠지만 결과적으로 데이터 로딩 중에 페이지가 보이는 일을 방지하는게 목적이라면
CSR에서 많이 쓰이는 방법으로는 로딩, 스켈레톤, if(!data) return <></> 등이 있을 것 같네요
어쩔 수 없이 html 문서를 받아야하고, 랜더도 해야하고, useEffect가 돌아야 데이터 통신을 하고 그래야만 isError가 존재하는지 아닌지 알 수 있어서 그래요
react-query는 내부적으로
const useQuery = () => {
//...
useEffect(()=>{
queryFn();
},[])
//...
}
이렇게 생겼다고 상상하시면 좋을 것 같습니다!
즉, 페이지에 진입을 해야만 결과를 알 수 있는 것이죠...
getServerSideProps에서 관련 로직을 관리한다면 한템포 빨라질 것 같습니다만 페이지 전환 시에는 모호하네요.
따라서 로딩, 스켈레톤,if방어코드 등으로 우회할 수밖에 없을 것 같아요 ㅜㅠ
정말 더 개선 한다면 페이지 이동 전에 네트워크 통신을 하고 성공 시에만 페이지 전환을 하는 방법도 있지만, 존재하지 않는 id가 리스트업 되어있는게 잘못된 상황이라 이런 경우는 거의 없을 것 같아요...!
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.
isloading, isfetch도 적절히 고려하면 좋을 것 같습니다(다른 상황에서)
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.
이부분~!!!! 너무너무 꿀팁 꿀정보라 코멘트 꼭 남겨야지 하다가 시간을 넘겨버렸네요, 넘 죄송하고 피드백 너무너무 감사합니다...!!! 덕분에 저도 여러모로 배워갑니다.
그럼 우선 이 부분은 스켈레톤 ui를 만들어볼까 싶어용. 말씀대로 폴더id를 미리 리스트업해두는건 맞지 않으니 다른 식으로 우회해야 할 거 같네요. 좋은 방법 알려주셔서 넘 감사합니다!!!!
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.tsx에서 queryClient를 컴포넌트 외부에서 선언하면 해결이 됩니다 ㅎㅎ
이게 컴포넌트 밖에 있으면 '한번'만 선언되고 쭉 유지가 되는데 컴포넌트 내부에 있으면 여러가지 요인으로 재선언 되는데 그러면 객체가 새거가 되어서 캐시가 날아가는 이슈가 있어요!
React-query에서 뿐만 아니라 이러한 이슈 때문에 useMemo, useCallback 등이 사용된답니다!
전반적으로 코드 정리가 아주 잘되어있네요 재사용도 적재적소되어있고 파일도 분리가 잘 되어있고 불필요한 코드가 거의 없는 것 같아요 컴포넌트도 잘 운용하셔서 굳이 다음 챌린지가 있다면 mui처럼 같은 만능 공용 모듈� 관련하여 알아보면 도움이 되실거라 생각합니다!
적어도 컴포넌트의 사용, 훅의 사용 측면에서는 지금까지 본 코드 중에서 가장 잘 사용하셨다고 생각합니다 재원님의 방식을 주변 분들에게 널리 알려주셔도 좋을 것 같아요!
위클리 하시느라 고생 많으셨고 프로젝트에 재원님이 좋은 기여를 해주실 것 같아 든든한 생각이 듭니다!
궁금한점 대댓글(태그꼭), DM, 궁금궁금 편하게 남겨주세요! 이번 주도 화이팅입니다~!~!
@@ -1,11 +1,13 @@ | |||
import { UserType } from "@/types/UserType"; | |||
import { axiosInstance } from "./axiosInstance"; | |||
|
|||
// 로그인된 유저의 정보를 조회하는 api |
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.
정리가 아주 잘되어있네요!!
|
||
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; | ||
} | ||
|
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.
저는 useEffect는 css를 입히고 시작하므로 맨 처음 setState시 깜빡임을 개선하기 위해 useLayoutEffect를 쓰면 css 입히기 전에 동작한다고 알고 있어용
그래서 현 상황은 네트워크 통신이 완료 되어야 결과를 알 수 있는거라서 useLayoutEffect는 솔루션이 아니겠다는 생각이구용.
- 먼저 페이지 이동을 함 -> 2. 네트워크 통신을 함 -> 3. 기다림 -> 4. 결과를 알게됨(isError)
이미 2번 단계 진입 시 useLayoutEffect의 효능은 끝났다고 알고있습니다
따라서,
5초나 걸리는지는 모르겠지만 결과적으로 데이터 로딩 중에 페이지가 보이는 일을 방지하는게 목적이라면
CSR에서 많이 쓰이는 방법으로는 로딩, 스켈레톤, if(!data) return <></> 등이 있을 것 같네요
어쩔 수 없이 html 문서를 받아야하고, 랜더도 해야하고, useEffect가 돌아야 데이터 통신을 하고 그래야만 isError가 존재하는지 아닌지 알 수 있어서 그래요
react-query는 내부적으로
const useQuery = () => {
//...
useEffect(()=>{
queryFn();
},[])
//...
}
이렇게 생겼다고 상상하시면 좋을 것 같습니다!
즉, 페이지에 진입을 해야만 결과를 알 수 있는 것이죠...
getServerSideProps에서 관련 로직을 관리한다면 한템포 빨라질 것 같습니다만 페이지 전환 시에는 모호하네요.
따라서 로딩, 스켈레톤,if방어코드 등으로 우회할 수밖에 없을 것 같아요 ㅜㅠ
정말 더 개선 한다면 페이지 이동 전에 네트워크 통신을 하고 성공 시에만 페이지 전환을 하는 방법도 있지만, 존재하지 않는 id가 리스트업 되어있는게 잘못된 상황이라 이런 경우는 거의 없을 것 같아요...!
<DndProvider backend={HTML5Backend}> | ||
<div className={styles["card-list-section"]}> | ||
<CardListWrapper folderId={folderId} keyword={keyword} /> | ||
</div> | ||
</DndProvider> |
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.
제가 아주 좋아하는 주석들이네요 👍 이런 정보가 쌓일 수록 귀한 자산이 된다고 생각합니다
|
||
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; | ||
} | ||
|
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.
isloading, isfetch도 적절히 고려하면 좋을 것 같습니다(다른 상황에서)
const handleCloseDropdown = () => { | ||
setTimeout(() => setIsOpen(false), 200); | ||
}; | ||
const { isOpen, handleOpen, handleClose } = useDropdown(); |
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 { mutate } = useMutation({ | ||
onMutate: () => setFakeFilled(!fakeFilled), | ||
mutationFn: () => updateCardFavorite(cardId, !isFilled), | ||
onSettled: () => { | ||
setFakeFilled(isFilled); | ||
queryClient.invalidateQueries({ queryKey: ["card-list"] }); | ||
}, | ||
}); |
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.
@@ -1,26 +1,57 @@ | |||
/*Card 컴포넌트*/ | |||
|
|||
import Link from "next/link"; | |||
import { useDrag, useDrop } from "react-dnd"; |
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.
신기하고 간결한 라이브러리네요!
머지하겠습니다! |
@yusunghyun 멘토님 피드백대로 한 번 다시 플젝 리팩토링 해보겠습니다, 늘 감사합니다!!! |
요구사항
기본
심화
주요 변경사항
스크린샷
멘토에게