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

[백승렬] Week 19 #496

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"dependencies": {
"@popperjs/core": "^2.11.8",
"@tanstack/react-query": "^5.48.0",
"axios": "^1.6.8",
"classnames": "^2.5.1",
"date-fns": "^3.6.0",
Expand Down
8 changes: 7 additions & 1 deletion pages/_app.tsx
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>
);
}
65 changes: 65 additions & 0 deletions pages/folder/[[...folderId]]/index.tsx
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(() => {
Copy link
Collaborator

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는 의존성 배열이 필요한데, 이 배열에 들어간 값들이 변경될 때마다 메모이제이션 된 값을 무효화하고 새로 계산한다. 이 과정에서 복잡성이 증가하며, 관리가 미흡한 경우 오히려 성능이 저하될 수 있다.

남용에 따른 실수: 무분별한 사용으로 인해 모든 함수나 결과값을 메모이제이션하려 할 때 실수가 발생할 가능성이 높아진다. 이로 인해 성능 최적화를 기대하는 대신 버그나 성능 저하를 초래할 수 있는 상황이 생길 수 있다.

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;
42 changes: 0 additions & 42 deletions pages/folder/index.tsx

This file was deleted.

17 changes: 11 additions & 6 deletions pages/shared/index.tsx → pages/shared/[folderId]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useGetFolder } from "@/src/data-access";
import { useGetFolder, useGetUser, useGetSharedLinks } from "@/src/data-access";
import {
CardList,
Layout,
Expand All @@ -8,10 +8,15 @@ import {
} from "@/src/ui";
import { SharedLayout } from "@/src/page-layout/SharedLayout";
import { useSearchLink } from "@/src/util";
import { useRouter } from "next/router";

const SharedPage = () => {
const { data } = useGetFolder();
const { profileImage, ownerName, folderName, links } = data || {};
const router = useRouter();
const { folderId } = router.query;
const { data: folder } = useGetFolder(folderId as string);
const { data: owner } = useGetUser(folder.userId);
const { data: links } = useGetSharedLinks(folder.userId, folderId as string);

const { searchValue, handleChange, handleCloseClick, result } =
useSearchLink(links);

Expand All @@ -20,9 +25,9 @@ const SharedPage = () => {
<SharedLayout
folderInfo={
<FolderInfo
profileImage={profileImage}
ownerName={ownerName}
folderName={folderName}
profileImage={owner.imageSource}
ownerName={owner.name}
folderName={folder.name}
/>
}
searchBar={
Expand Down
11 changes: 10 additions & 1 deletion src/data-access/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,13 @@ export * from "./useGetFolders";
export * from "./useGetLinks"
export * from "./useSignIn";
export * from "./useSignUp";
export * from "./useCheckEmailDuplicate";
export * from "./useCheckEmailDuplicate";
export * from "./useGetSharedLinks"
export * from "./useGetCurrentUser"
export * from "./useDeleteLink"
export * from "./useAddLink"
export * from "./useAddFolder"
export * from "./useDeleteFolder"
export * from "./useUpdateFolderName"
export * from "./useSignIn"
export * from "./useSignUp"
23 changes: 23 additions & 0 deletions src/data-access/useAddFolder.ts
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 = () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The 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 };
};
28 changes: 28 additions & 0 deletions src/data-access/useAddLink.ts
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 };
};
21 changes: 16 additions & 5 deletions src/data-access/useCheckEmailDuplicate.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { instance, useAsync } from "@/src/util";
import { instance } from "../util";
import { useQuery } from "@tanstack/react-query";
import { AxiosError } from "axios";
import { useCallback } from "react";

/**
Expand All @@ -21,16 +23,25 @@ import { useCallback } from "react";
export const useCheckEmailDuplicate = (email: string) => {
const checkEmailDuplicate = useCallback(
() =>
instance.post<{ data: { isUsableNickname: boolean } }>("check-email", {
instance.post<Response>("/users/check-email", {
email,
}),
[email]
);
const { execute, loading, error, data } = useAsync(checkEmailDuplicate, true);
const { data, error, isLoading, refetch } = useQuery<
{ data: Response },
AxiosError
>({
queryKey: ["check-email"],
queryFn: checkEmailDuplicate,
enabled: false,
retry: false,
networkMode: "always",
});

return {
execute,
loading,
refetch,
isLoading,
error,
data,
};
Expand Down
21 changes: 21 additions & 0 deletions src/data-access/useDeleteFolder.ts
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 };
};
26 changes: 26 additions & 0 deletions src/data-access/useDeleteLink.ts
Copy link
Collaborator

Choose a reason for hiding this comment

The 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 };
};
Loading
Loading