From 7548ad27483efbc25808f415a8f0a4a2d7a7279d Mon Sep 17 00:00:00 2001 From: Chiman2937 Date: Tue, 24 Feb 2026 14:21:56 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20zustand=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 ++- pnpm-lock.yaml | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 7e74f292..35ff5cad 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,8 @@ "sockjs-client": "^1.6.1", "swiper": "^12.0.3", "tailwind-merge": "^3.3.1", - "zod": "^4.1.13" + "zod": "^4.1.13", + "zustand": "^5.0.11" }, "devDependencies": { "@commitlint/cli": "^20.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d6badda1..18cc80e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,6 +68,9 @@ importers: zod: specifier: ^4.1.13 version: 4.1.13 + zustand: + specifier: ^5.0.11 + version: 5.0.11(@types/react@19.2.2)(immer@9.0.21)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)) devDependencies: '@commitlint/cli': specifier: ^20.1.0 @@ -7060,6 +7063,24 @@ packages: zod@4.1.13: resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} + zustand@5.0.11: + resolution: {integrity: sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + snapshots: '@adobe/css-tools@4.4.4': {} @@ -15588,3 +15609,10 @@ snapshots: zod: 4.1.13 zod@4.1.13: {} + + zustand@5.0.11(@types/react@19.2.2)(immer@9.0.21)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)): + optionalDependencies: + '@types/react': 19.2.2 + immer: 9.0.21 + react: 19.2.3 + use-sync-external-store: 1.6.0(react@19.2.3) From 885fd639918082e04bf745254595808604195e19 Mon Sep 17 00:00:00 2001 From: Chiman2937 Date: Tue, 24 Feb 2026 14:23:25 +0900 Subject: [PATCH 2/6] =?UTF-8?q?fix:=20=EC=A0=84=EC=97=AD=EC=83=81=ED=83=9C?= =?UTF-8?q?=203=EC=A2=85=20store=EB=A1=9C=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stores/index.ts | 2 ++ src/stores/useAuthStore/index.ts | 11 +++++++++++ src/stores/useNotificationStore/index.ts | 17 +++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 src/stores/index.ts create mode 100644 src/stores/useAuthStore/index.ts create mode 100644 src/stores/useNotificationStore/index.ts diff --git a/src/stores/index.ts b/src/stores/index.ts new file mode 100644 index 00000000..80c4f6c2 --- /dev/null +++ b/src/stores/index.ts @@ -0,0 +1,2 @@ +export { useAuthStore } from './useAuthStore'; +export { useNotificationStore } from './useNotificationStore'; diff --git a/src/stores/useAuthStore/index.ts b/src/stores/useAuthStore/index.ts new file mode 100644 index 00000000..251ed7f8 --- /dev/null +++ b/src/stores/useAuthStore/index.ts @@ -0,0 +1,11 @@ +import { create } from 'zustand'; + +interface AuthState { + isAuthenticated: boolean; + setIsAuthenticated: (value: boolean) => void; +} + +export const useAuthStore = create((set) => ({ + isAuthenticated: false, + setIsAuthenticated: (value) => set({ isAuthenticated: value }), +})); diff --git a/src/stores/useNotificationStore/index.ts b/src/stores/useNotificationStore/index.ts new file mode 100644 index 00000000..1866c1f2 --- /dev/null +++ b/src/stores/useNotificationStore/index.ts @@ -0,0 +1,17 @@ +import { create } from 'zustand'; + +import { NotificationItem } from '@/types/service/notification'; + +interface AuthState { + receivedData: NotificationItem | null; + setReceivedData: (value: NotificationItem | null) => void; + hasNewNotification: boolean; + setHasNewNotification: (value: boolean) => void; +} + +export const useNotificationStore = create((set) => ({ + receivedData: null, + setReceivedData: (value) => set({ receivedData: value }), + hasNewNotification: false, + setHasNewNotification: (value) => set({ hasNewNotification: value }), +})); From fdf1e4ab0ff853fcf61e54eedd41f9e7e54f4783 Mon Sep 17 00:00:00 2001 From: Chiman2937 Date: Tue, 24 Feb 2026 14:27:42 +0900 Subject: [PATCH 3/6] =?UTF-8?q?fix:=20AuthProvider=20-=20context=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=EA=B5=AC=EB=AC=B8=20=EC=82=AD=EC=A0=9C,?= =?UTF-8?q?=20zustand=20store=EB=A1=9C=20=EC=83=81=ED=83=9C=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/layout/gnb/index.tsx | 4 +-- src/components/layout/header/index.tsx | 4 +-- .../auth/login/login-toast-effect/index.tsx | 4 +-- src/hooks/use-auth/use-auth-login/index.ts | 4 +-- src/hooks/use-auth/use-auth-logout/index.ts | 4 +-- src/providers/index.ts | 2 +- src/providers/provider-auth/index.tsx | 27 ++++++------------- 7 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/components/layout/gnb/index.tsx b/src/components/layout/gnb/index.tsx index 4558de1b..64de01c3 100644 --- a/src/components/layout/gnb/index.tsx +++ b/src/components/layout/gnb/index.tsx @@ -4,12 +4,12 @@ import Link from 'next/link'; import { usePathname } from 'next/navigation'; import { Icon } from '@/components/icon'; -import { useAuth } from '@/providers'; +import { useAuthStore } from '@/stores'; export const GNB = () => { const pathname = usePathname(); - const { isAuthenticated } = useAuth(); + const { isAuthenticated } = useAuthStore(); const highLightPath = (path: string) => { if (path === '/') { diff --git a/src/components/layout/header/index.tsx b/src/components/layout/header/index.tsx index 4a2a4a73..1b18be77 100644 --- a/src/components/layout/header/index.tsx +++ b/src/components/layout/header/index.tsx @@ -5,10 +5,10 @@ import Link from 'next/link'; import { Icon } from '@/components/icon'; import { CowBell } from '@/components/layout/header/cow-bell'; import { HeaderLogin } from '@/components/layout/header/header-login'; -import { useAuth } from '@/providers'; +import { useAuthStore } from '@/stores'; export const Header = () => { - const { isAuthenticated } = useAuth(); + const { isAuthenticated } = useAuthStore(); return (
diff --git a/src/components/pages/auth/login/login-toast-effect/index.tsx b/src/components/pages/auth/login/login-toast-effect/index.tsx index a8a46ce2..c4bafdef 100644 --- a/src/components/pages/auth/login/login-toast-effect/index.tsx +++ b/src/components/pages/auth/login/login-toast-effect/index.tsx @@ -4,7 +4,7 @@ import { useEffect, useRef } from 'react'; import { Toast } from '@/components/ui'; import { useToast } from '@/components/ui/toast/core'; -import { useAuth } from '@/providers'; +import { useAuthStore } from '@/stores'; type Props = { error?: string | string[]; @@ -12,7 +12,7 @@ type Props = { export const LoginToastEffect = ({ error }: Props) => { const { run } = useToast(); - const { setIsAuthenticated } = useAuth(); + const { setIsAuthenticated } = useAuthStore(); const lastErrorRef = useRef(''); useEffect(() => { diff --git a/src/hooks/use-auth/use-auth-login/index.ts b/src/hooks/use-auth/use-auth-login/index.ts index 45165489..38a305d2 100644 --- a/src/hooks/use-auth/use-auth-login/index.ts +++ b/src/hooks/use-auth/use-auth-login/index.ts @@ -8,7 +8,7 @@ import axios, { AxiosError } from 'axios'; import { API } from '@/api'; import { normalizePath } from '@/lib/auth/utils'; -import { useAuth } from '@/providers'; +import { useAuthStore } from '@/stores'; import { LoginRequest } from '@/types/service/auth'; import { CommonErrorResponse } from '@/types/service/common'; @@ -29,7 +29,7 @@ export const useLogin = () => { const [loginError, setLoginError] = useState(null); const clearLoginError = useCallback(() => setLoginError(null), []); - const { setIsAuthenticated } = useAuth(); + const { setIsAuthenticated } = useAuthStore(); const handleLogin = async (payload: LoginRequest, formApi: { reset: () => void }) => { setLoginError(null); diff --git a/src/hooks/use-auth/use-auth-logout/index.ts b/src/hooks/use-auth/use-auth-logout/index.ts index 905fcd78..85507978 100644 --- a/src/hooks/use-auth/use-auth-logout/index.ts +++ b/src/hooks/use-auth/use-auth-logout/index.ts @@ -4,12 +4,12 @@ import { useQueryClient } from '@tanstack/react-query'; import { API } from '@/api'; import { userKeys } from '@/lib/query-key/query-key-user'; -import { useAuth } from '@/providers'; +import { useAuthStore } from '@/stores'; export const useLogout = () => { const queryClient = useQueryClient(); - const { setIsAuthenticated } = useAuth(); + const { setIsAuthenticated } = useAuthStore(); const handleLogout = async () => { try { diff --git a/src/providers/index.ts b/src/providers/index.ts index 7d96907e..7ecc1093 100644 --- a/src/providers/index.ts +++ b/src/providers/index.ts @@ -1,4 +1,4 @@ -export { AuthProvider, useAuth } from './provider-auth'; +export { AuthProvider } from './provider-auth'; export { LazyMotionProvider } from './provider-lazy-motion'; export { MSWProvider } from './provider-msw'; export { NotificationProvider, useNotification } from './provider-notification'; diff --git a/src/providers/provider-auth/index.tsx b/src/providers/provider-auth/index.tsx index 902ae969..adc44f08 100644 --- a/src/providers/provider-auth/index.tsx +++ b/src/providers/provider-auth/index.tsx @@ -1,17 +1,6 @@ -import React, { createContext, SetStateAction, useContext, useState } from 'react'; +import { useEffect } from 'react'; -interface AuthContextType { - isAuthenticated: boolean; - setIsAuthenticated: React.Dispatch>; -} - -const AuthContext = createContext(null); - -export const useAuth = () => { - const context = useContext(AuthContext); - if (!context) throw new Error('useAuth must be used in AuthProvider'); - return context; -}; +import { useAuthStore } from '@/stores'; interface Props { children: React.ReactNode; @@ -19,11 +8,11 @@ interface Props { } export const AuthProvider = ({ children, hasRefreshToken }: Props) => { - const [isAuthenticated, setIsAuthenticated] = useState(hasRefreshToken); + const { setIsAuthenticated } = useAuthStore(); + + useEffect(() => { + setIsAuthenticated(hasRefreshToken); + }, [hasRefreshToken, setIsAuthenticated]); - return ( - - {children} - - ); + return <>{children}; }; From 6d34e3c01cbc9871e58a290e871a7c377b5132c4 Mon Sep 17 00:00:00 2001 From: Chiman2937 Date: Tue, 24 Feb 2026 14:33:01 +0900 Subject: [PATCH 4/6] =?UTF-8?q?fix:=20NotificationStore=20-=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EB=AA=85=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stores/useNotificationStore/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stores/useNotificationStore/index.ts b/src/stores/useNotificationStore/index.ts index 1866c1f2..0e144b87 100644 --- a/src/stores/useNotificationStore/index.ts +++ b/src/stores/useNotificationStore/index.ts @@ -2,14 +2,14 @@ import { create } from 'zustand'; import { NotificationItem } from '@/types/service/notification'; -interface AuthState { +interface NotificationState { receivedData: NotificationItem | null; setReceivedData: (value: NotificationItem | null) => void; hasNewNotification: boolean; setHasNewNotification: (value: boolean) => void; } -export const useNotificationStore = create((set) => ({ +export const useNotificationStore = create((set) => ({ receivedData: null, setReceivedData: (value) => set({ receivedData: value }), hasNewNotification: false, From 0e4c4f508ed6b2610758a9bc1d3ea6451c5e843e Mon Sep 17 00:00:00 2001 From: Chiman2937 Date: Tue, 24 Feb 2026 14:39:40 +0900 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20useNotificationUnreadCount=20-=20use?= =?UTF-8?q?AuthStore=20=ED=98=B8=EC=B6=9C=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../use-notification-get-unread-count/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hooks/use-notification/use-notification-get-unread-count/index.ts b/src/hooks/use-notification/use-notification-get-unread-count/index.ts index 51741e09..c81f851f 100644 --- a/src/hooks/use-notification/use-notification-get-unread-count/index.ts +++ b/src/hooks/use-notification/use-notification-get-unread-count/index.ts @@ -2,10 +2,10 @@ import { useQuery } from '@tanstack/react-query'; import { API } from '@/api'; import { notificationKeys } from '@/lib/query-key/query-key-notification'; -import { useAuth } from '@/providers'; +import { useAuthStore } from '@/stores'; export const useGetNotificationUnreadCount = () => { - const { isAuthenticated } = useAuth(); + const { isAuthenticated } = useAuthStore(); const queryResult = useQuery({ queryKey: notificationKeys.unReadCount(), queryFn: () => API.notificationService.getUnreadCount(), @@ -14,10 +14,10 @@ export const useGetNotificationUnreadCount = () => { retry: false, }); - const finalData = isAuthenticated ? (queryResult.data ?? 0) : 0; + const unReadCount = isAuthenticated ? (queryResult.data ?? 0) : 0; return { ...queryResult, - data: finalData, + unReadCount, }; }; From e4774f3b9b3bd3e1cafa8c292609fe300d712bb0 Mon Sep 17 00:00:00 2001 From: Chiman2937 Date: Tue, 24 Feb 2026 14:53:08 +0900 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20AuthProvider=20-=20use=20client=20?= =?UTF-8?q?=EC=A7=80=EC=8B=9C=EC=96=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/providers/provider-auth/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/providers/provider-auth/index.tsx b/src/providers/provider-auth/index.tsx index adc44f08..8b181cb5 100644 --- a/src/providers/provider-auth/index.tsx +++ b/src/providers/provider-auth/index.tsx @@ -1,3 +1,4 @@ +'use client'; import { useEffect } from 'react'; import { useAuthStore } from '@/stores';