diff --git a/src/app/App.tsx b/src/app/App.tsx
index a76a0c6..cad867e 100644
--- a/src/app/App.tsx
+++ b/src/app/App.tsx
@@ -2,7 +2,9 @@ import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { RouterProvider } from 'react-router-dom';
-import { queryClient } from './providers/query-client';
+import { queryClient } from '@/shared/react-query';
+import { NetworkErrorToast } from '@/shared/ui';
+
import { router } from './routers/index';
import './styles/global.scss';
@@ -10,6 +12,8 @@ function App() {
return (
+
+
);
diff --git a/src/app/providers/query-client.ts b/src/app/providers/query-client.ts
deleted file mode 100644
index 1c134b9..0000000
--- a/src/app/providers/query-client.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { QueryClient, QueryClientConfig } from '@tanstack/react-query';
-
-const queryClientOptions: QueryClientConfig = {
- defaultOptions: {
- queries: {
- staleTime: 10 * 60 * 1000, // 10 minutes
- gcTime: 15 * 60 * 1000, // 15 minutes
- refetchOnWindowFocus: false,
- retry: false,
- },
- },
-};
-export const queryClient = new QueryClient(queryClientOptions);
diff --git a/src/app/styles/_reset.scss b/src/app/styles/_reset.scss
index 8063ff5..a3a0a85 100644
--- a/src/app/styles/_reset.scss
+++ b/src/app/styles/_reset.scss
@@ -126,6 +126,10 @@ button {
background-color: transparent;
border: none;
padding: 0;
+
+ &:disabled {
+ color: inherit;
+ }
}
.icon {
diff --git a/src/features/feed-main-like/api/useLikes.tsx b/src/features/feed-main-like/api/useLikes.tsx
index f64894f..3d46a4f 100644
--- a/src/features/feed-main-like/api/useLikes.tsx
+++ b/src/features/feed-main-like/api/useLikes.tsx
@@ -1,7 +1,7 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { requestLikeFeed, requestUnlikeFeed } from '@/shared/axios';
-import { QUERY_KEYS } from '@/shared/consts';
+import { QUERY_KEYS } from '@/shared/react-query';
import { isErrorResponse } from '@/shared/utils';
import { FeedsQueryData } from '../consts';
diff --git a/src/shared/consts/index.ts b/src/shared/consts/index.ts
index 783d4c4..58cd54c 100644
--- a/src/shared/consts/index.ts
+++ b/src/shared/consts/index.ts
@@ -1,3 +1,2 @@
-export { QUERY_KEYS } from './query-key/queryKeys';
export type * from './types';
export * from './color';
diff --git a/src/shared/react-query/consts/client.ts b/src/shared/react-query/consts/client.ts
new file mode 100644
index 0000000..a2e6b12
--- /dev/null
+++ b/src/shared/react-query/consts/client.ts
@@ -0,0 +1,31 @@
+import {
+ MutationCache,
+ QueryCache,
+ QueryClient,
+ QueryClientConfig,
+} from '@tanstack/react-query';
+
+import {
+ handleMutationError,
+ handleQueryError,
+ handleQuerySuccess,
+} from '../dir';
+
+const queryClientOptions: QueryClientConfig = {
+ defaultOptions: {
+ queries: {
+ staleTime: 10 * 60 * 1000, // 10 minutes
+ gcTime: 15 * 60 * 1000, // 15 minutes
+ refetchOnWindowFocus: false,
+ retry: false,
+ },
+ },
+ queryCache: new QueryCache({
+ onSuccess: () => handleQuerySuccess(),
+ onError: (_, query) => handleQueryError(query),
+ }),
+ mutationCache: new MutationCache({
+ onError: () => handleMutationError(),
+ }),
+};
+export const queryClient = new QueryClient(queryClientOptions);
diff --git a/src/shared/react-query/consts/index.ts b/src/shared/react-query/consts/index.ts
new file mode 100644
index 0000000..94adb01
--- /dev/null
+++ b/src/shared/react-query/consts/index.ts
@@ -0,0 +1,2 @@
+export { queryClient } from './client';
+export { QUERY_KEYS } from './keys';
diff --git a/src/shared/consts/query-key/queryKeys.ts b/src/shared/react-query/consts/keys.ts
similarity index 100%
rename from src/shared/consts/query-key/queryKeys.ts
rename to src/shared/react-query/consts/keys.ts
diff --git a/src/shared/react-query/dir/handleQuery.ts b/src/shared/react-query/dir/handleQuery.ts
new file mode 100644
index 0000000..505b0f4
--- /dev/null
+++ b/src/shared/react-query/dir/handleQuery.ts
@@ -0,0 +1,31 @@
+import { Query, QueryKey } from '@tanstack/react-query';
+
+import { removeErrorHandler, showErrorHandler } from './toastHandlers';
+
+/**
+ * 쿼리 성공 핸들러
+ */
+export function handleQuerySuccess() {
+ removeErrorHandler();
+}
+
+/**
+ * 쿼리 에러 핸들러 함수
+ * @param query 쿼리
+ * @if 피드 메인 페이지 2 페이지부터 에러가 발생하면 네트워크 에러 토스트를 띄웁니다.
+ */
+export function handleQueryError(
+ query: Query,
+) {
+ const { queryKey, state } = query;
+
+ // feeds 쿼리에서 2 페이지부터 에러가 발생하면 네트워크 에러 토스트를 띄웁니다.
+ if (queryKey[0] === 'feeds' && state.data) showErrorHandler();
+}
+
+/**
+ * 뮤테이션 에러 핸들러
+ */
+export function handleMutationError() {
+ return;
+}
diff --git a/src/shared/react-query/dir/index.ts b/src/shared/react-query/dir/index.ts
new file mode 100644
index 0000000..e591523
--- /dev/null
+++ b/src/shared/react-query/dir/index.ts
@@ -0,0 +1,2 @@
+export * from './handleQuery';
+export * from './toastHandlers';
diff --git a/src/shared/react-query/dir/toastHandlers.ts b/src/shared/react-query/dir/toastHandlers.ts
new file mode 100644
index 0000000..a682bf7
--- /dev/null
+++ b/src/shared/react-query/dir/toastHandlers.ts
@@ -0,0 +1,27 @@
+import { Bounce, toast } from 'react-toastify';
+
+const id = 'react-query-toast';
+
+/**
+ * 에러 메시지를 토스트 메시지로 변환합니다.
+ */
+export function showErrorHandler() {
+ // reference: https://fkhadra.github.io/react-toastify/api/toast
+ if (!toast.isActive(id)) {
+ toast('인터넷 연결이 불안정해요', {
+ toastId: id,
+ autoClose: 3000,
+ position: 'bottom-center',
+ transition: Bounce,
+ });
+ }
+}
+
+/**
+ * 에러 메시지 토스트를 제거합니다.
+ */
+export function removeErrorHandler() {
+ if (toast.isActive(id)) {
+ toast.dismiss(id);
+ }
+}
diff --git a/src/shared/react-query/index.ts b/src/shared/react-query/index.ts
new file mode 100644
index 0000000..208236d
--- /dev/null
+++ b/src/shared/react-query/index.ts
@@ -0,0 +1 @@
+export * from './consts';
diff --git a/src/shared/ui/network-error-toast/NetworkErrorToast.scss b/src/shared/ui/network-error-toast/NetworkErrorToast.scss
index b22760c..9060361 100644
--- a/src/shared/ui/network-error-toast/NetworkErrorToast.scss
+++ b/src/shared/ui/network-error-toast/NetworkErrorToast.scss
@@ -29,7 +29,7 @@
.Toastify__close-button,
.Toastify__progress-bar--wrp {
- display: none;
+ visibility: hidden;
}
}
}
diff --git a/src/shared/ui/network-error-toast/NetworkErrorToast.tsx b/src/shared/ui/network-error-toast/NetworkErrorToast.tsx
index 9c29008..d902788 100644
--- a/src/shared/ui/network-error-toast/NetworkErrorToast.tsx
+++ b/src/shared/ui/network-error-toast/NetworkErrorToast.tsx
@@ -1,47 +1,17 @@
-import { useEffect, useRef } from 'react';
-import { ToastContainer, toast } from 'react-toastify';
+import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import './NetworkErrorToast.scss';
import { Icon } from '..';
-interface NetworkToastErrorProps {
- isVisible: boolean;
- errorMessage: string;
-}
-
-export const NetworkErrorToast: React.FC = ({
- isVisible,
- errorMessage,
-}) => {
- const toastId = useRef(-1);
-
- useEffect(() => {
- // 에러 메시지가 보여야 하고, 현재 토스트가 표시되지 않았다면,
- // 새로운 토스트를 표시하고 그 ID를 toastId에 저장합니다.
- if (isVisible && toastId.current === -1) {
- toastId.current = toast(errorMessage);
- return;
- }
-
- // 에러 메시지가 보여지지 않아야 하고, 현재 토스트가 표시되어 있다면,
- // 토스트를 제거하고 toastId를 초기화합니다.
- if (!isVisible && toastId.current !== -1) {
- toast.dismiss(toastId.current);
- toastId.current = -1;
- return;
- }
- }, [isVisible, errorMessage]);
-
+export const NetworkErrorToast = () => {
return (
}
- hideProgressBar={true}
- rtl={false}
limit={1}
+ pauseOnHover={false}
+ pauseOnFocusLoss={false}
theme='colored'
/>
);
diff --git a/src/widgets/feed-main-list/api/useInfinityFeeds.tsx b/src/widgets/feed-main-list/api/useInfinityFeeds.tsx
index ba997fd..e3d080e 100644
--- a/src/widgets/feed-main-list/api/useInfinityFeeds.tsx
+++ b/src/widgets/feed-main-list/api/useInfinityFeeds.tsx
@@ -1,7 +1,8 @@
import { useInfiniteQuery } from '@tanstack/react-query';
import { axiosInstance } from '@/shared/axios';
-import { FetchFeeds, QUERY_KEYS } from '@/shared/consts';
+import { FetchFeeds } from '@/shared/consts';
+import { QUERY_KEYS } from '@/shared/react-query';
async function fetchFeeds(
page: number,
diff --git a/src/widgets/feed-main-list/ui/FeedMainList.tsx b/src/widgets/feed-main-list/ui/FeedMainList.tsx
index 90be68d..0f94eca 100644
--- a/src/widgets/feed-main-list/ui/FeedMainList.tsx
+++ b/src/widgets/feed-main-list/ui/FeedMainList.tsx
@@ -1,4 +1,4 @@
-import { NetworkError, NetworkErrorToast, Observer } from '@/shared/ui';
+import { NetworkError, Observer } from '@/shared/ui';
import { useInfinityFeeds } from '../api/useInfinityFeeds';
@@ -42,10 +42,6 @@ export const FeedMainList = () => {
)}
{hasNextFeeds && }
-
);
};