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

♻️ Refactor: 폴더 구조 변경 및 react-query 구조 개선 #56

Merged
merged 34 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4f381b9
♻️ refactor: 공통 컴포넌트 이동
ojj1123 Jun 12, 2023
c40a014
♻️ refactor: 공통 hook 이동
ojj1123 Jun 12, 2023
02418ff
♻️ refactor: 공통 유틸 이동
ojj1123 Jun 12, 2023
ef5be12
♻️ refactor: 공통 컴포넌트 경로 추가 변경
ojj1123 Jun 12, 2023
80079a4
♻️ refactor: 서드파티라이브러리 파일 이동
ojj1123 Jun 12, 2023
9570210
🔧 update(tailwind.config.js): content 설정 변경
ojj1123 Jun 18, 2023
cf20414
🐛 fix(next.config.js): 빌드 에러 해결
ojj1123 Jun 18, 2023
b8d91b5
♻️ refactor: 공통 컴포넌트, hook 이동 (#54)
ojj1123 Jun 18, 2023
9a9989c
♻️ refactor: 홈 화면 컴포넌트 이동
ojj1123 Jun 24, 2023
5b8f3e0
♻️ refactor: 밈 상세 화면 컴포넌트 이동, feature간 공통 컴포넌트 이동
ojj1123 Jul 4, 2023
b3d0c32
♻️ refactor: 마이페이지 컴포넌트 이동
ojj1123 Jul 4, 2023
799a298
♻️ refactor: 콜렉션 페이지 컴포넌트 이동
ojj1123 Jul 4, 2023
3c33230
♻️ refactor: 검색 페이지 컴포넌트 이동
ojj1123 Jul 14, 2023
74f0ac4
♻️ refactor: 태그, 키워드 검색결과 페이지 컴포넌트 이동
ojj1123 Jul 14, 2023
f98ae70
♻️ refactor: 공유 밈 페이지 컴포넌트 이동
ojj1123 Jul 14, 2023
cd3f7a0
♻️ refactor: hocs 폴더 이동
ojj1123 Jul 14, 2023
76906d6
♻️ refactor(SkeletonTagList): 사용하지 않는 컴포넌트 삭제
ojj1123 Jul 14, 2023
73accf9
♻️ refactor: 도메인 hook 폴더 이동
ojj1123 Jul 14, 2023
b23a065
♻️ refactor: useAuth hook 이동
ojj1123 Jul 14, 2023
06c3ebc
♻️ refactor: 페이지 별 컴포넌트, hook 이동 (#58)
ojj1123 Jul 17, 2023
baa8bbe
♻️ refactor: react-query core 파일 이동
ojj1123 Jul 18, 2023
a1fa512
♻️ refactor: axios 인스턴스 코드 이동
ojj1123 Jul 21, 2023
39153b8
♻️ refactor: meme 도메인 API 파일 이동
ojj1123 Jul 21, 2023
5ec202a
♻️ refactor: tag 도메인 파일 이동
ojj1123 Jul 21, 2023
e663439
♻️ refactor: collection 도메인 파일 이동
ojj1123 Jul 21, 2023
5a5354b
♻️ refactor: search 도메인 파일 이동
ojj1123 Jul 21, 2023
0007c6a
♻️ refactor: account 도메인 파일 이동
ojj1123 Jul 21, 2023
82eae87
♻️ refactor: QueryClientProvider 파일 이동
ojj1123 Jul 21, 2023
e578df0
⚰️ remove: /infra/api/index.ts 파일 삭제
ojj1123 Jul 21, 2023
8e8bc12
refactor: react query 커스텀 hook 파일 리펙터링 (#61)
ojj1123 Jul 22, 2023
45305bf
🔧 fix(tailwind.config.js): content 옵션 수정
ojj1123 Jul 22, 2023
29f51fb
🐛 fix(preview.js): storybook 오류 수정(컴포넌트 경로 수정)
ojj1123 Jul 22, 2023
854713b
⚰️ remove: 지라 티켓 넘버 husky
ojj1123 Jul 22, 2023
3f10810
🔥 remove: 스토리북 오류 파일 삭제
ojj1123 Jul 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 0 additions & 18 deletions .husky/prepare-commit-msg

This file was deleted.

31 changes: 17 additions & 14 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { initialize, mswDecorator } from "msw-storybook-addon";
import "@/styles/globals.css";
import { handlers } from "../mocks/handlers";
import * as NextImage from "next/image";
import { QueryClientProvider } from "../src/application/queryClient";
import { QueryClientProvider } from "../src/api/core";
import { Suspense } from "react";
import { RouterContext } from "next/dist/shared/lib/router-context";
import { ToastContainer, ToastProvider } from "../src/components/common/Toast";
import { SignUpModal, SignUpModalProvider } from "../src/components/common/Modal";
import { ToastContainer, ToastProvider } from "../src/common/components/Toast";
import { SignUpModal, SignUpModalProvider } from "../src/common/components/Modal";
import { OverlayProvider } from "../src/common/hooks";

// Initialize MSW
initialize();
Expand All @@ -16,17 +17,19 @@ export const decorators = [
mswDecorator,
(Story) => (
<QueryClientProvider>
<ToastProvider>
<SignUpModalProvider>
<Suspense fallback="loading...">
<div className="__font_family_variables font-pretendard">
<ToastContainer />
<SignUpModal />
<Story />
</div>
</Suspense>
</SignUpModalProvider>
</ToastProvider>
<OverlayProvider>
<ToastProvider>
<SignUpModalProvider>
<Suspense fallback="loading...">
<div className="__font_family_variables font-pretendard">
<ToastContainer />
<SignUpModal />
<Story />
</div>
</Suspense>
</SignUpModalProvider>
</ToastProvider>
</OverlayProvider>
</QueryClientProvider>
),
];
Expand Down
8 changes: 1 addition & 7 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,7 @@ const IS_DEV = process.env.NODE_ENV === "development";
const IS_PROD = process.env.NODE_ENV === "production";

// The folders containing files importing twin.macro
const includedDirs = [
path.resolve(__dirname, "./src/application"),
path.resolve(__dirname, "./src/components"),
path.resolve(__dirname, "./src/infra"),
path.resolve(__dirname, "./src/pages"),
path.resolve(__dirname, "./src/styles"),
];
const includedDirs = [path.resolve(__dirname, "./src")];

// eslint-disable-next-line @typescript-eslint/no-var-requires
const withPWA = require("next-pwa")({
Expand Down
2 changes: 2 additions & 0 deletions src/api/account/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./useGetMyAccount";
export * from "./useLogout";
19 changes: 19 additions & 0 deletions src/api/account/useGetMyAccount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useQuery, useQueryClient } from "@tanstack/react-query";

import { api } from "../core";

export const useGetMyAccount = () => {
const queryClient = useQueryClient();
return useQuery({
suspense: false,
queryKey: useGetMyAccount.queryKey,
queryFn: useGetMyAccount.queryFn,
onError: () => {
queryClient.setQueryData(useGetMyAccount.queryKey, null);
},
});
};

useGetMyAccount.queryKey = ["getMyAccount"] as const;

useGetMyAccount.queryFn = () => api.account.getMyAccount();
15 changes: 15 additions & 0 deletions src/api/account/useLogout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";

import { api } from "../core";
import { useGetMyAccount } from "./useGetMyAccount";

export const useLogout = () => {
const queryClient = useQueryClient();

return useMutation(api.auth.logout, {
onSuccess: () => {
api.auth.deleteAccessToken();
queryClient.setQueryData(useGetMyAccount.queryKey, null);
},
});
};
4 changes: 4 additions & 0 deletions src/api/collection/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./useDeleteMemeFromCollection";
export * from "./useGetCollectionCheck";
export * from "./usePostMemeToCollection";
export * from "./usePostMemeToSharedCollection";
40 changes: 40 additions & 0 deletions src/api/collection/useDeleteMemeFromCollection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";

import { useGetMyAccount } from "../account";
import { api } from "../core";
import { useGetCollectionCheck } from "./useGetCollectionCheck";
/**
* 콜렉션 삭제 API
*/
export const useDeleteMemeFromCollection = () => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: api.collection.deleteMemeFromCollection,
onMutate: async (deletedMemeId) => {
await queryClient.cancelQueries({
queryKey: useGetCollectionCheck.queryKey(deletedMemeId),
});

const previousCollectionInfo = queryClient.getQueryData(
useGetCollectionCheck.queryKey(deletedMemeId),
);

queryClient.setQueryData(useGetCollectionCheck.queryKey(deletedMemeId), {
collectionId: null,
isAdded: false,
});

return { previousCollectionInfo, deletedMemeId };
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: useGetMyAccount.queryKey });
},
onError: (_, deletedMemeId, context) => {
queryClient.setQueryData(
useGetCollectionCheck.queryKey(deletedMemeId),
context?.previousCollectionInfo,
);
},
});
};
29 changes: 29 additions & 0 deletions src/api/collection/useGetCollectionCheck.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { QueryClient, UseQueryOptions } from "@tanstack/react-query";
import { useQuery } from "@tanstack/react-query";

import { api } from "../core";

/**
* 밈별 콜렉션 정보 API
*/
export const useGetCollectionCheck = (
memeId: number,
options?: Pick<UseQueryOptions, "enabled">,
) => {
return useQuery({
queryKey: useGetCollectionCheck.queryKey(memeId),
queryFn: () => useGetCollectionCheck.queryFn(memeId),
suspense: false,
...options,
});
};

useGetCollectionCheck.queryKey = (memeId: number) => ["getCollectionCheck", memeId] as const;

useGetCollectionCheck.queryFn = (memeId: number) => api.collection.getCollectionCheck(memeId);

useGetCollectionCheck.prefetchQuery = (memeId: number, queryClient: QueryClient) =>
queryClient.prefetchQuery({
queryKey: useGetCollectionCheck.queryKey(memeId),
queryFn: () => useGetCollectionCheck.queryFn(memeId),
});
40 changes: 40 additions & 0 deletions src/api/collection/usePostMemeToCollection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";

import { useGetMyAccount } from "../account";
import { api } from "../core";
import { useGetCollectionCheck } from "./useGetCollectionCheck";
/**
* 콜렉션 저장 API
*/
export const usePostMemeToCollection = () => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: api.collection.postMemeToCollection,
onMutate: async (newMemeId) => {
await queryClient.cancelQueries({
queryKey: useGetCollectionCheck.queryKey(newMemeId),
});

const previousCollectionInfo = queryClient.getQueryData(
useGetCollectionCheck.queryKey(newMemeId),
);

queryClient.setQueryData(useGetCollectionCheck.queryKey(newMemeId), {
collectionId: 1,
isAdded: true,
});

return { previousCollectionInfo, newMemeId };
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: useGetMyAccount.queryKey });
},
onError: (_, newMemeId, context) => {
queryClient.setQueryData(
useGetCollectionCheck.queryKey(newMemeId),
context?.previousCollectionInfo,
);
},
});
};
23 changes: 23 additions & 0 deletions src/api/collection/usePostMemeToSharedCollection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";

import { useGetMyAccount } from "../account";
import { api } from "../core";
import { useGetMemesByCollectionId } from "../meme";

export const usePostMemeToSharedCollection = ({
memeId,
sharedId,
}: {
memeId: number;
sharedId: number;
}) => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: () => api.collection.postMemeToSharedCollection(memeId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: useGetMemesByCollectionId.queryKey(sharedId) });
queryClient.invalidateQueries({ queryKey: useGetMyAccount.queryKey });
},
});
};
9 changes: 4 additions & 5 deletions src/infra/api/index.ts → src/api/core/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import axios from "axios";

import { AccountApi } from "@/infra/api/account";
import { AuthApi } from "@/infra/api/auth";

import { CollectionApi } from "./collection";
import { MemeApi } from "./meme";
import { SearchApi } from "./search";
import { TagApi } from "./tags";
import { CollectionApi } from "@/infra/api/collection";
import { MemeApi } from "@/infra/api/meme";
import { SearchApi } from "@/infra/api/search";
import { TagApi } from "@/infra/api/tags";

export const axiosBasic = axios.create({
baseURL: `${process.env.NEXT_PUBLIC_API_URL}`,
Expand Down
5 changes: 5 additions & 0 deletions src/api/core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from "./axios";
export * from "./query-client";
export * from "./queryKey";
export * from "./useCoreInfiniteQuery";
export * from "./useSuspensedQuery";
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import {
QueryClientProvider as TanStackQueryClientProvider,
} from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import type { ReactNode } from "react";
import type { ComponentProps, ReactNode } from "react";
import { useState } from "react";

export interface DefaultPageProps {
hydrateState: ComponentProps<typeof QueryClientProvider>["hydrateState"];
}

interface Props {
hydrateState?: DehydratedState;
children: ReactNode;
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,13 +1,41 @@
import type { QueryFunction, QueryKey } from "@tanstack/react-query";
import type {
QueryFunction,
QueryKey,
UseQueryOptions,
UseQueryResult,
} from "@tanstack/react-query";
import { useQuery } from "@tanstack/react-query";

import type {
BaseSuspendedUseQueryResult,
SuspendedUseQueryOptions,
SuspendedUseQueryResultOnIdle,
SuspendedUseQueryResultOnSuccess,
} from "@/application/hooks/api/core/types";
export interface BaseSuspendedUseQueryResult<TData>
extends Omit<
UseQueryResult<TData, never>,
"data" | "status" | "error" | "isLoading" | "isError" | "isFetching"
> {
data: TData;
status: "success" | "idle";
}

export type SuspendedUseQueryResultOnSuccess<TData> = BaseSuspendedUseQueryResult<TData> & {
status: "success";
isSuccess: true;
isIdle: false;
};
export type SuspendedUseQueryResultOnIdle<TData> = BaseSuspendedUseQueryResult<TData> & {
status: "idle";
isSuccess: false;
isIdle: true;
};

export type SuspendedUseQueryOptions<
TQueryFnData = unknown,
TError = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
> = Omit<UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, "suspense">;

export type QuerySelectOption<Result, API extends (...args: any) => any> = (
data: Awaited<ReturnType<API>>,
) => Result;
/**
* @desc suspense 사용 시 non-nullable data 이도록 wrapping
* @link https://github.com/toss/slash/blob/main/packages/react/react-query/src/hooks/useSuspendedQuery.ts
Expand Down
3 changes: 3 additions & 0 deletions src/api/meme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./useGetMemeDetailById";
export * from "./useGetMemesByCollectionId";
export * from "./useGetMemesBySort";
24 changes: 24 additions & 0 deletions src/api/meme/useGetMemeDetailById.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { QueryClient } from "@tanstack/react-query";

import { api, useSuspendedQuery } from "../core";

/**
* 밈 상세 조회 API
* @param id 상세 조회할 밈 id
*/
export const useGetMemeDetailById = (id: string) => {
const { data, isRefetching } = useSuspendedQuery({
queryKey: useGetMemeDetailById.queryKey(id),
queryFn: () => useGetMemeDetailById.queryFn(id),
staleTime: Infinity,
});

return { ...data, isRefetching };
};

useGetMemeDetailById.queryKey = (id: string) => ["getMemeDetailById", id] as const;

useGetMemeDetailById.queryFn = (id: string) => api.meme.getMemeDetailById(id);

useGetMemeDetailById.fetchQuery = (id: string, queryClient: QueryClient) =>
queryClient.fetchQuery(useGetMemeDetailById.queryKey(id), () => api.meme.getMemeDetailById(id));
Loading