diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 109d5ea..850c07d 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,6 +3,8 @@ import '@/src/styles/globals.css'; import { pretendard } from '@/src/styles/fonts'; import QueryProvider from '@/src/components/primitives/QueryProvider'; import AuthProvicder from '@/src/components/primitives/AuthProvider'; +import { Suspense } from 'react'; +import LoadingSpinner from '@/src/components/primitives/LoadingSpinner'; export const metadata: Metadata = { title: 'Global Nomad', @@ -18,7 +20,9 @@ export default function RootLayout({ - {children} + + }>{children} +
diff --git a/src/components/pages/main/AllExperiencesSection.tsx b/src/components/pages/main/AllExperiencesSection.tsx index bf55ade..9c186f6 100644 --- a/src/components/pages/main/AllExperiencesSection.tsx +++ b/src/components/pages/main/AllExperiencesSection.tsx @@ -39,10 +39,10 @@ export default function AllExperiencesSection() { const totalCount = allExperiences?.totalCount; const lastPage = totalCount && Math.ceil(totalCount / size); - if (lastPage && size > lastPage) { + if (lastPage && page > lastPage) { setPage(lastPage); } - }, [allExperiences, size]); + }, [allExperiences, size, page]); return (
diff --git a/src/components/pages/main/SearchResultSection.tsx b/src/components/pages/main/SearchResultSection.tsx index 375e2b4..f746a5a 100644 --- a/src/components/pages/main/SearchResultSection.tsx +++ b/src/components/pages/main/SearchResultSection.tsx @@ -21,10 +21,10 @@ export default function SearchResultSection() { const totalCount = resultList?.totalCount; const lastPage = totalCount && Math.ceil(totalCount / size); - if (lastPage && size > lastPage) { + if (lastPage && page > lastPage) { setPage(lastPage); } - }, [size, resultList]); + }, [resultList, size, page]); useEffect(() => { // 검색값이 변경되면, 페이지네이션 초기화 diff --git a/src/components/primitives/AuthProvider.tsx b/src/components/primitives/AuthProvider.tsx index 92bdf08..28b9e6a 100644 --- a/src/components/primitives/AuthProvider.tsx +++ b/src/components/primitives/AuthProvider.tsx @@ -5,30 +5,37 @@ import { queries } from '@/src/services/primitives/queries'; import { useTokenStore } from '@/src/store/useTokenStore'; import { useQuery } from '@tanstack/react-query'; import { usePathname, useRouter } from 'next/navigation'; -import { ReactNode, useEffect } from 'react'; +import { ReactNode, useEffect, useState } from 'react'; interface Props { children: ReactNode; } export default function AuthProvicder({ children }: Props) { + const [isAuthChecked, setIsAuthCheck] = useState(null); const pathname = usePathname(); const router = useRouter(); const accessToken = useTokenStore((state) => state.accessToken); // 리액트쿼리는 액세스 토큰이 있고, 유효한 액세스 토큰을 넘겨주었을 때에만 페칭을 시작함. - const { isLoading, data: userInfo } = useQuery({ + const { isLoading } = useQuery({ ...queries.userOptions(accessToken), retry: false, staleTime: Infinity, }); - // 리다이렉트 분기 useEffect(() => { - // accessToken이 undefined 이거나 리액트 쿼리 페칭중이라면 return - if (accessToken === undefined || isLoading) return; + if (!!accessToken) { + setIsAuthCheck(true); + } else { + setIsAuthCheck(false); + } + }, [accessToken]); - const isLoggingIn = !!userInfo; + // 리다이렉트 분기 + useEffect(() => { + // 리액트 쿼리 페칭중이라면 return + if (isAuthChecked === null || isLoading) return; const AUTH_PATHS = [ '/login', @@ -44,7 +51,7 @@ export default function AuthProvicder({ children }: Props) { ); // 로그인 상태일때 - if (isLoggingIn) { + if (isAuthChecked) { // auth 페이지(로그인/회원가입) 라우트시 if (isAuthPath) { router.replace('/'); @@ -52,17 +59,17 @@ export default function AuthProvicder({ children }: Props) { } // 로그인 상태가 아닐 때 - if (!isLoggingIn) { + if (!isAuthChecked) { // 프로텍트 페이지 (/, /detail, /login, /signup 제외) 접속시 if (!isPublicPath && !isAuthPath) { // 로그인페이지로 리다이렉트, 이때 params에 ?&redirect_uri=현재페이지경로 를 추가해줘서 로그인 완료시 접속시도했던 페이지로 리다이렉트되도록 처리 router.replace(`/login?redirect_path=${pathname}`); } } - }, [pathname, router, accessToken, isLoading, userInfo]); + }, [pathname, router, isLoading, isAuthChecked]); - // // accessToken이 undefined 이거나 리액트 쿼리 페칭중이라면 로딩 보여주기. - if (accessToken === undefined || isLoading) + // 리액트 쿼리 페칭중이라면 로딩 보여주기. + if (isLoading) return (
diff --git a/src/components/primitives/toast/ToastContainer.tsx b/src/components/primitives/toast/ToastContainer.tsx index 73b3b56..335d1d8 100644 --- a/src/components/primitives/toast/ToastContainer.tsx +++ b/src/components/primitives/toast/ToastContainer.tsx @@ -1,3 +1,5 @@ +'use client'; + import Toast from '@/src/components/primitives/toast/Toast'; import { useToastStore } from '@/src/store/useToastStore'; import { createPortal } from 'react-dom'; @@ -5,6 +7,8 @@ import { createPortal } from 'react-dom'; export default function ToastContainer() { const toasts = useToastStore((state) => state.toasts); + if (toasts.length === 0) return; + return createPortal(
{toasts.map((toast, idx) => ( diff --git a/src/store/useTokenStore.ts b/src/store/useTokenStore.ts index 6f56494..019957d 100644 --- a/src/store/useTokenStore.ts +++ b/src/store/useTokenStore.ts @@ -2,7 +2,7 @@ import { create } from 'zustand'; import { createJSONStorage, persist } from 'zustand/middleware'; interface TokenState { - accessToken: null | string | undefined; + accessToken: null | string; setAccessToken: (token: string | null) => void; deleteAccessToken: () => void; } @@ -11,7 +11,7 @@ export const useTokenStore = create()( persist( (set) => { return { - accessToken: undefined, + accessToken: null, setAccessToken: (token) => set({ accessToken: token }), deleteAccessToken: () => set({ accessToken: null }), }; @@ -19,11 +19,6 @@ export const useTokenStore = create()( { name: 'accessToken', storage: createJSONStorage(() => localStorage), - onRehydrateStorage: () => (state) => { - if (state?.accessToken === undefined) { - state?.setAccessToken(null); - } - }, } ) );