-
Notifications
You must be signed in to change notification settings - Fork 46
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
[백승렬] Week 19 #496
[백승렬] Week 19 #496
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,12 @@ | ||
import { queryClient } from "@/src/util"; | ||
import "@/styles/reset.css"; | ||
import { QueryClientProvider } from "@tanstack/react-query"; | ||
import type { AppProps } from "next/app"; | ||
|
||
export default function App({ Component, pageProps }: AppProps) { | ||
return <Component {...pageProps} />; | ||
return ( | ||
<QueryClientProvider client={queryClient}> | ||
<Component {...pageProps} /> | ||
</QueryClientProvider> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { CardList, FolderToolBar, LinkForm } from "@/src/feature"; | ||
import { Layout, SearchBar } from "@/src/ui"; | ||
import { FolderLayout } from "@/src/page-layout/FolderLayout"; | ||
import { | ||
useIntersectionObserver, | ||
useSearchLink, | ||
ALL_LINKS_ID, | ||
} from "@/src/util"; | ||
import { useGetLinks, useGetFolders } from "@/src/data-access"; | ||
import { ROUTE } from "@/src/util"; | ||
import { useRouter } from "next/router"; | ||
import { useEffect, useMemo } from "react"; | ||
|
||
const FolderPage = () => { | ||
const router = useRouter(); | ||
const { folderId } = router.query; | ||
const currentFolderId = useMemo(() => { | ||
if (router.isReady) { | ||
return folderId?.[0] ? parseInt(folderId?.[0]) : ALL_LINKS_ID; | ||
} | ||
return undefined; | ||
}, [router.isReady, folderId]); | ||
const { data: folders } = useGetFolders(); | ||
const { data: links, loading } = useGetLinks(currentFolderId); | ||
const { searchValue, handleChange, handleCloseClick, result } = | ||
useSearchLink(links); | ||
const { ref, isIntersecting } = useIntersectionObserver<HTMLDivElement>(); | ||
|
||
useEffect(() => { | ||
const accessToken = localStorage.getItem("accessToken"); | ||
if (!accessToken) { | ||
router.replace(ROUTE.로그인); | ||
} | ||
}, [router]); | ||
|
||
return ( | ||
<Layout isSticky={false} footerRef={ref}> | ||
<FolderLayout | ||
linkForm={ | ||
<LinkForm | ||
hideFixedLinkForm={isIntersecting} | ||
currentFolderId={currentFolderId} | ||
/> | ||
} | ||
searchBar={ | ||
<SearchBar | ||
value={searchValue} | ||
onChange={handleChange} | ||
onCloseClick={handleCloseClick} | ||
/> | ||
} | ||
folderToolBar={ | ||
<FolderToolBar folders={folders} selectedFolderId={currentFolderId} /> | ||
} | ||
cardList={ | ||
loading ? null : ( | ||
<CardList links={result} currentFolderId={currentFolderId} /> | ||
) | ||
} | ||
/> | ||
</Layout> | ||
); | ||
}; | ||
|
||
export default FolderPage; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { instance } from "../util"; | ||
import { FolderRawData } from "../type"; | ||
import { useMutation } from "@tanstack/react-query"; | ||
import { useGetFolders } from "."; | ||
|
||
type Params = { name: string }; | ||
|
||
export const useAddFolder = () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 커스텀훅 좋습니다 👍 |
||
const { refetch } = useGetFolders(); | ||
const addFolder = ({ name }: Params) => | ||
instance.post<FolderRawData[]>("/folders", { | ||
name, | ||
}); | ||
|
||
const { mutate } = useMutation({ | ||
mutationKey: ["addFolder"], | ||
mutationFn: addFolder, | ||
onSuccess: () => refetch(), | ||
retry: false, | ||
}); | ||
|
||
return { mutate }; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { instance } from "../util"; | ||
import { useMutation } from "@tanstack/react-query"; | ||
import { useGetLinks, useGetFolders } from "."; | ||
import { LinkRawData, SelectedFolderId } from "../type"; | ||
|
||
type Params = { url: string; folderId: number }; | ||
|
||
export const useAddLink = (folderId?: SelectedFolderId) => { | ||
const { refetch: getLinks } = useGetLinks(folderId); | ||
const { refetch: getFolders } = useGetFolders(); | ||
const addLink = ({ url, folderId }: Params) => | ||
instance.post<LinkRawData[]>("/links", { | ||
url, | ||
folderId, | ||
}); | ||
|
||
const { mutate } = useMutation({ | ||
mutationKey: ["addLink"], | ||
mutationFn: addLink, | ||
onSuccess: () => { | ||
getLinks(); | ||
getFolders(); | ||
}, | ||
retry: false, | ||
}); | ||
|
||
return { mutate }; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { instance } from "../util"; | ||
import { FolderRawData } from "../type"; | ||
import { useMutation } from "@tanstack/react-query"; | ||
import { useGetFolders } from "."; | ||
|
||
type Params = { folderId: number }; | ||
|
||
export const useDeleteFolder = () => { | ||
const { refetch } = useGetFolders(); | ||
const deleteFolder = ({ folderId }: Params) => | ||
instance.delete<FolderRawData[]>(`/folders/${folderId}`); | ||
|
||
const { mutate } = useMutation({ | ||
mutationKey: ["deleteFolder"], | ||
mutationFn: deleteFolder, | ||
onSuccess: () => refetch(), | ||
retry: false, | ||
}); | ||
|
||
return { mutate }; | ||
}; |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 커스텀훅 별로 파일을 나누는 것도 좋지만 같은 타입의 api 호출이라면 한 파일에 묶어주시는 것도 좋아요 예를 들면, // useCustomLink.ts
export const useAddLink = () => {}
export const useDeleteLink = () => {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { instance, queryClient } from "../util" | ||
import { useMutation } from "@tanstack/react-query"; | ||
import { useGetLinks, useGetFolders } from "."; | ||
import { LinkRawData, SelectedFolderId } from "../type"; | ||
|
||
type Params = { linkId: number }; | ||
|
||
export const useDeleteLink = (folderId?: SelectedFolderId) => { | ||
const { refetch: getLinks } = useGetLinks(folderId); | ||
const { refetch: getFolders } = useGetFolders(); | ||
const deleteLink = ({ linkId }: Params) => | ||
instance.delete<LinkRawData[]>(`/links/${linkId}`); | ||
|
||
const { mutate } = useMutation({ | ||
mutationKey: ["deleteLink"], | ||
mutationFn: deleteLink, | ||
onSuccess: () => { | ||
getLinks(); | ||
getFolders(); | ||
queryClient.invalidateQueries({ queryKey: ["getLinks", folderId] }); | ||
}, | ||
retry: false, | ||
}); | ||
|
||
return { mutate }; | ||
}; |
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.
여기서 굳이 useMemo를 사용하신 이유가 있으시다면?!
useMemo를 사용하면 값을 메모이제이션할 수 있다는 장점이 있지만 반대로 비용이 많이 들어가는 방법이에요!
잘못됬다는 것은 아닙니다! 다만 알아두면 좋은 내용이에요 :)
남용하지 말아야할 이유
useCallback과 useMemo는 성능 최적화의 목적으로 사용되긴 하지만, 무분별하게 사용할 경우 오히려 성능 저하를 초래할 수 있다.
메모이제이션 자체의 비용: 이 두 Hook을 사용하면 함수와 계산 결과를 캐싱하기 위한 메모리 사용량이 늘어난다. 게다가, 새롭게 계산되는 값이 일정 기간 동안 사용되지 않아도 메모리에 남아 있어야 하므로 메모리 관리의 측면에서 비효율적일 수 있다. (가비지 컬렉터가 무시)
의존성 배열의 관리: useCallback과 useMemo는 의존성 배열이 필요한데, 이 배열에 들어간 값들이 변경될 때마다 메모이제이션 된 값을 무효화하고 새로 계산한다. 이 과정에서 복잡성이 증가하며, 관리가 미흡한 경우 오히려 성능이 저하될 수 있다.
남용에 따른 실수: 무분별한 사용으로 인해 모든 함수나 결과값을 메모이제이션하려 할 때 실수가 발생할 가능성이 높아진다. 이로 인해 성능 최적화를 기대하는 대신 버그나 성능 저하를 초래할 수 있는 상황이 생길 수 있다.