Skip to content

Comments

[Refactor] 전역 상태(isAuthenticated) Context API → Zustand Store 전환#393

Merged
Chiman2937 merged 6 commits intomainfrom
chiyoung-refactor/auth-state
Feb 24, 2026
Merged

[Refactor] 전역 상태(isAuthenticated) Context API → Zustand Store 전환#393
Chiman2937 merged 6 commits intomainfrom
chiyoung-refactor/auth-state

Conversation

@Chiman2937
Copy link
Member

@Chiman2937 Chiman2937 commented Feb 24, 2026

📝 변경 사항

Zustand Store 도입 변경사항

브랜치: chiyoung-refactor/state
커밋 범위: 7548ad2 ~ 0e4c4f5 (5개 커밋)
변경 파일: 13개 (83 additions, 35 deletions)


커밋 히스토리

커밋 메시지
7548ad2 feat: zustand 설치
885fd63 fix: 전역상태 3종 store로 전환
fdf1e4a fix: AuthProvider - context 관리 구문 삭제, zustand store로 상태 관리 전환
6d34e3c fix: NotificationStore - 인터페이스 명 수정
0e4c4f5 fix: useNotificationUnreadCount - useAuthStore 호출로 수정

1. Zustand 도입 및 Store 생성

zustand@5.0.11 설치 후, 기존 Context API로 관리하던 클라이언트 전역 상태를 Zustand Store로 전환.

상태 관리 원칙

상태 유형 관리 도구 예시
클라이언트 전역 상태 Zustand isAuthenticated, hasNewNotification
서버 상태 React Query unReadCount, 유저 정보, 모임 목록 등
로컬 상태 useState 폼 입력값, UI 토글 등

기존 NotificationProvider에서 Context로 관리하던 unReadCount는 서버 상태이므로 React Query에서만 관리하도록 하고 전역 상태에서 제거. useNotificationStore에는 클라이언트 상태(receivedData, hasNewNotification)만 포함.

신규 디렉토리 구조

src/stores/
  ├── index.ts                          ← re-export
  ├── useAuthStore/index.ts             ← 인증 상태 store
  └── useNotificationStore/index.ts     ← 알림 상태 store

useAuthStore

interface AuthState {
  isAuthenticated: boolean;
  setIsAuthenticated: (value: boolean) => void;
}

export const useAuthStore = create<AuthState>((set) => ({
  isAuthenticated: false,
  setIsAuthenticated: (value) => set({ isAuthenticated: value }),
}));

useNotificationStore

interface NotificationState {
  receivedData: NotificationItem | null;
  setReceivedData: (value: NotificationItem | null) => void;
  hasNewNotification: boolean;
  setHasNewNotification: (value: boolean) => void;
}

export const useNotificationStore = create<NotificationState>((set) => ({
  receivedData: null,
  setReceivedData: (value) => set({ receivedData: value }),
  hasNewNotification: false,
  setHasNewNotification: (value) => set({ hasNewNotification: value }),
}));

2. AuthProvider - Context → Zustand 전환

src/providers/provider-auth/index.tsx에서 Context API 기반 상태 관리를 완전히 제거하고, Zustand store의 초기값만 설정하는 역할로 변경.

Before - Context API 기반

interface AuthContextType {
  isAuthenticated: boolean;
  setIsAuthenticated: React.Dispatch<SetStateAction<boolean>>;
}

const AuthContext = createContext<AuthContextType | null>(null);

export const useAuth = () => {
  const context = useContext(AuthContext);
  if (!context) throw new Error('useAuth must be used in AuthProvider');
  return context;
};

export const AuthProvider = ({ children, hasRefreshToken }: Props) => {
  const [isAuthenticated, setIsAuthenticated] = useState(hasRefreshToken);

  return (
    <AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated }}>
      {children}
    </AuthContext.Provider>
  );
};

After - Zustand store 초기값 설정만 담당

import { useAuthStore } from '@/stores';

export const AuthProvider = ({ children, hasRefreshToken }: Props) => {
  const { setIsAuthenticated } = useAuthStore();

  useEffect(() => {
    setIsAuthenticated(hasRefreshToken);
  }, [hasRefreshToken, setIsAuthenticated]);

  return <>{children}</>;
};

삭제된 항목

  • AuthContext (createContext)
  • AuthContextType 인터페이스
  • useAuth 훅 (Context 기반)
  • useState 기반 상태 관리
  • AuthContext.Provider wrapper

3. 컴포넌트/훅 import 경로 변경

기존 useAuth (Context) → useAuthStore (Zustand)로 모든 참조를 변경.

파일 Before After
components/layout/gnb/index.tsx useAuth from @/providers useAuthStore from @/stores
components/layout/header/index.tsx useAuth from @/providers useAuthStore from @/stores
components/pages/auth/login/login-toast-effect/index.tsx useAuth from @/providers useAuthStore from @/stores
hooks/use-auth/use-auth-login/index.ts useAuth from @/providers useAuthStore from @/stores
hooks/use-auth/use-auth-logout/index.ts useAuth from @/providers useAuthStore from @/stores
hooks/use-notification/use-notification-get-unread-count/index.ts useAuth from @/providers useAuthStore from @/stores

사용 방식은 동일하게 유지:

// Before
const { isAuthenticated } = useAuth();
const { setIsAuthenticated } = useAuth();

// After
const { isAuthenticated } = useAuthStore();
const { setIsAuthenticated } = useAuthStore();

4. providers/index.ts re-export 정리

useAuth가 삭제되었으므로 providers/index.ts에서 해당 export 제거.

// Before
export { AuthProvider, useAuth } from './provider-auth';

// After
export { AuthProvider } from './provider-auth';

5. useGetNotificationUnreadCount 반환값 변경

src/hooks/use-notification/use-notification-get-unread-count/index.ts에서 useAuthuseAuthStore로 변경하고, 반환값의 프로퍼티명을 dataunReadCount로 변경.

// Before
const finalData = isAuthenticated ? (queryResult.data ?? 0) : 0;
return { ...queryResult, data: finalData };

// After
const unReadCount = isAuthenticated ? (queryResult.data ?? 0) : 0;
return { ...queryResult, unReadCount };

추가 발견사항

1. useNotificationStore는 후속 PR에서 적용 예정

useNotificationStore가 생성되었으나, 기존 NotificationProvider의 Context를 대체하는 작업은 후속 PR에서 진행 예정. 전환 시 unReadCount는 서버 상태이므로 store에 포함하지 않고 React Query에서만 관리하며, 클라이언트 상태(receivedData, hasNewNotification)만 store로 이관.


변경된 파일 목록

파일 변경 유형
package.json 수정 (zustand 의존성 추가)
pnpm-lock.yaml 수정 (lock file 갱신)
src/stores/index.ts 신규 (re-export)
src/stores/useAuthStore/index.ts 신규 (인증 상태 store)
src/stores/useNotificationStore/index.ts 신규 (알림 상태 store)
src/providers/provider-auth/index.tsx 수정 (Context 제거, Zustand 초기값 설정)
src/providers/index.ts 수정 (useAuth export 제거)
src/components/layout/gnb/index.tsx 수정 (useAuthStore 적용)
src/components/layout/header/index.tsx 수정 (useAuthStore 적용)
src/components/pages/auth/login/login-toast-effect/index.tsx 수정 (useAuthStore 적용)
src/hooks/use-auth/use-auth-login/index.ts 수정 (useAuthStore 적용)
src/hooks/use-auth/use-auth-logout/index.ts 수정 (useAuthStore 적용)
src/hooks/use-notification/use-notification-get-unread-count/index.ts 수정 (useAuthStore 적용, 반환값 변경)

🔗 관련 이슈

Closes #


🧪 테스트 방법

  • 수동 테스트 검증(로컬 환경)
  • 유닛 테스트 검증
  • 통합 테스트 검증

📸 스크린샷 (선택)


📋 체크리스트

  • 관련 문서를 업데이트했습니다 (필요한 경우)
  • 테스트를 추가/수정했습니다 (필요한 경우)
  • Breaking change가 있다면 명시했습니다

💬 추가 코멘트


CodeRabbit Review는 자동으로 실행되지 않습니다.

Review를 실행하려면 comment에 아래와 같이 작성해주세요

@coderabbitai review

Summary by CodeRabbit

  • 리팩토링
    • 내부 상태 관리 체계를 개선하여 애플리케이션의 안정성과 유지보수성을 강화했습니다. 사용자가 체감하는 앱의 기능과 동작은 변경되지 않습니다.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

인증 상태 관리를 React Context 기반의 Provider에서 Zustand 스토어 기반으로 마이그레이션합니다. 새로운 useAuthStoreuseNotificationStore 스토어를 생성하고, 기존 컴포넌트와 훅들을 업데이트하여 새로운 스토어를 사용하도록 변경합니다.

Changes

Cohort / File(s) Summary
의존성 추가
package.json
Zustand (^5.0.11) 의존성 추가
Zustand 스토어 생성
src/stores/useAuthStore/index.ts, src/stores/useNotificationStore/index.ts
새로운 인증 및 알림 상태 관리 스토어 생성. 각 스토어는 해당 상태와 setter 함수 제공
스토어 Export 추가
src/stores/index.ts
새로운 스토어 훅 useAuthStore, useNotificationStore 공개 export
AuthProvider 리팩토링
src/providers/provider-auth/index.tsx
Context 기반 인증 구현을 Zustand 스토어 기반으로 변경. useAuthStore를 도입하고 hasRefreshToken 변경 시 상태 업데이트
Provider Export 정리
src/providers/index.ts
useAuth export 제거
컴포넌트에서 스토어 사용으로 전환
src/components/layout/gnb/index.tsx, src/components/layout/header/index.tsx, src/components/pages/auth/login/login-toast-effect/index.tsx
useAuth() 호출을 useAuthStore()로 변경. Import 소스를 @/providers에서 @/stores로 수정
훅에서 스토어 사용으로 전환
src/hooks/use-auth/use-auth-login/index.ts, src/hooks/use-auth/use-auth-logout/index.ts, src/hooks/use-notification/use-notification-get-unread-count/index.ts
인증 상태 관리 의존성을 useAuth에서 useAuthStore로 변경

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested labels

Ready For Review!

Suggested reviewers

  • wooktori
  • yoorli

Poem

🐰 Context에서 Store로 마법의 전환,
Zustand와 함께 상태는 더 빠르게 춤을 춘다.
Provider의 복잡함은 이제 안녕,
깔끔한 스토어로 모든 게 더 밝아졌네! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 변경사항의 핵심을 명확하게 반영하고 있습니다. Context API에서 Zustand Store로의 전환이라는 주요 목적이 간결하고 구체적으로 표현되었습니다.
Description check ✅ Passed PR 설명이 템플릿을 대부분 따르고 있으며, 변경 사항에 대한 상세한 설명과 함께 커밋 히스토리, 신규 디렉토리 구조, 코드 예시 등이 포함되어 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chiyoung-refactor/auth-state

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Feb 24, 2026

📊 Coverage Report

Status Build Log Updated (UTC)
✅ Ready View Build 2026-02-24 05:56:12

📈 #393main에 병합하면 coverage가 0.11% 증가합니다.

Coverage 요약

@@             Coverage Diff             @@
##             main     #393       +/-   ##
===========================================
+ Coverage   35.58%   35.69%    +0.11%     
===========================================
  Files         264      267        +3     
  Lines       12116    12136       +20     
  Branches      467      469        +2     
===========================================
+ Hits         4312     4332       +20     
  Misses       7804     7804         0     

영향받은 파일

파일 Coverage 변화
/home/runner/work/WeGo_FrontEnd/WeGo_FrontEnd/src/stores/index.ts 100.00% (+100.00%) ⬆️
/home/runner/work/WeGo_FrontEnd/WeGo_FrontEnd/src/stores/useAuthStore/index.ts 100.00% (+100.00%) ⬆️
/home/runner/work/WeGo_FrontEnd/WeGo_FrontEnd/src/stores/useNotificationStore/index.ts 100.00% (+100.00%) ⬆️

@github-actions
Copy link

github-actions bot commented Feb 24, 2026

🎨 Storybook Report

변경 사항이 없습니다

모든 Story가 이전 빌드와 동일합니다.

Status Storybook Build Log Updated (UTC)
✅ Unchanged View Storybook View Build 2026-02-24 05:57:34

@github-actions
Copy link

github-actions bot commented Feb 24, 2026

🎭 Playwright Report

E2E Test가 성공적으로 완료되었습니다.

Test 요약 내용을 확인해주세요.

Status Build Log Updated (UTC)
✅ Ready View Build 2026-02-24 05:57:17

📊 Test Summary

  • ✅ Passed: 3
  • ❌ Failed: 0
  • ⏱️ Duration: 37.9s

📜 Test Details

✅ Passed Tests (3)
  • profile.test.ts (3)
    • [chromium] 존재하지 않는 프로필 페이지로 접속 시 404 redirect 되는 지 테스트
    • [firefox] 존재하지 않는 프로필 페이지로 접속 시 404 redirect 되는 지 테스트
    • [webkit] 존재하지 않는 프로필 페이지로 접속 시 404 redirect 되는 지 테스트

@github-actions
Copy link

github-actions bot commented Feb 24, 2026

🚀 PR Preview Report

Build가 성공적으로 완료되었습니다.

Preview에서 변경사항을 확인하세요.

Status Preview Build Log Updated (UTC)
✅ Ready Visit Preview View Logs 2026-02-24 05:57:13

@Chiman2937
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/hooks/use-notification/use-notification-get-unread-count/index.ts`:
- Line 5: 훅 useGetNotificationUnreadCount가 이제 명시적 필드 unReadCount를 반환하므로 기존 소비
코드에서 `const { data: unReadCount = 0 }`로 가져오던 부분을 업데이트해야 합니다; 해당 소비자(예:
provider-notification의 destructure)에서 `const { data: unReadCount = 0 }`를 `const
{ unReadCount }`로 바꾸고, 필요하면 기본값 처리(예: undefined -> 0)는 소비자 쪽에서 안전하게 처리하도록 변경하여
필드 이름 정책을 통일하세요.

In `@src/providers/provider-auth/index.tsx`:
- Around line 1-17: Add the "use client" directive at the top of this module so
AuthProvider is explicitly a client component; update the top of the file before
any imports and ensure the module-level directive applies to the AuthProvider
component (which uses useAuthStore and useEffect) so its intent is explicit and
safe for future independent usage.

ℹ️ Review info

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8d82ad9 and 0e4c4f5.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • package.json
  • src/components/layout/gnb/index.tsx
  • src/components/layout/header/index.tsx
  • src/components/pages/auth/login/login-toast-effect/index.tsx
  • src/hooks/use-auth/use-auth-login/index.ts
  • src/hooks/use-auth/use-auth-logout/index.ts
  • src/hooks/use-notification/use-notification-get-unread-count/index.ts
  • src/providers/index.ts
  • src/providers/provider-auth/index.tsx
  • src/stores/index.ts
  • src/stores/useAuthStore/index.ts
  • src/stores/useNotificationStore/index.ts

import { API } from '@/api';
import { notificationKeys } from '@/lib/query-key/query-key-notification';
import { useAuth } from '@/providers';
import { useAuthStore } from '@/stores';
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n --type=ts --type=tsx "useGetNotificationUnreadCount" -C3

Repository: WeGo-Together/WeGo_FrontEnd

Length of output: 98


🏁 Script executed:

rg -n "useGetNotificationUnreadCount" -C3

Repository: WeGo-Together/WeGo_FrontEnd

Length of output: 2441


🏁 Script executed:

cat -n src/hooks/use-notification/use-notification-get-unread-count/index.ts

Repository: WeGo-Together/WeGo_FrontEnd

Length of output: 873


🏁 Script executed:

rg -n "useGetNotificationUnreadCount" --no-filename -B5 -A5 | grep -E "(data|unReadCount|useGetNotificationUnreadCount)" | head -30

Repository: WeGo-Together/WeGo_FrontEnd

Length of output: 487


useGetNotificationUnreadCount 훅의 반환 필드 정책 통일 필요

훅이 이제 명시적인 unReadCount 필드를 제공하므로, 기존 data 필드를 사용하던 소비자는 새로운 필드로 업데이트해야 합니다. src/providers/provider-notification/index.tsx 라인 24에서 const { data: unReadCount = 0 }const { unReadCount }로 변경해 주세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/use-notification/use-notification-get-unread-count/index.ts` at
line 5, 훅 useGetNotificationUnreadCount가 이제 명시적 필드 unReadCount를 반환하므로 기존 소비 코드에서
`const { data: unReadCount = 0 }`로 가져오던 부분을 업데이트해야 합니다; 해당 소비자(예:
provider-notification의 destructure)에서 `const { data: unReadCount = 0 }`를 `const
{ unReadCount }`로 바꾸고, 필요하면 기본값 처리(예: undefined -> 0)는 소비자 쪽에서 안전하게 처리하도록 변경하여
필드 이름 정책을 통일하세요.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unReadCount는 React Query로만 관리하고, 전역상태에 저장하지 않을 예정입니다.
사용되는 컴포넌트 마다 api를 호출하는 형태이지만, 캐시된 데이터를 호출하기 때문에 문제가 없습니다.

주요 포인트는 "서버상태는 React Query 로만 관리한다" 입니다.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the consumer code in provider-notification to see if it needs updating
cat -n src/providers/provider-notification/index.tsx | grep -A5 -B5 "useGetNotificationUnreadCount"

Length of output: 772


@Chiman2937, 설명 감사합니다! React Query로 서버 상태를 관리하는 아키텍처 결정에 동의합니다. 이는 서버 상태와 클라이언트 상태를 명확하게 분리하는 좋은 패턴입니다.

제 코멘트는 unReadCount를 Zustand로 옮기자는 의도가 아니었고, 단순히 필드명 일관성에 관한 것이었습니다. 현재 훅이 명시적으로 unReadCount 필드를 반환하는데, provider-notification/index.tsx의 24번째 라인에서 여전히 const { data: unReadCount = 0 }로 사용하고 있어서요. const { unReadCount }로 변경하면 훅의 의도가 더 명확해집니다.

다만 큰 이슈는 아니므로, 팀의 판단에 맡기겠습니다. 아키텍처 원칙 잘 이해했습니다! 👍


✏️ Learnings added
Learnt from: Chiman2937
Repo: WeGo-Together/WeGo_FrontEnd PR: 393
File: src/hooks/use-notification/use-notification-get-unread-count/index.ts:5-5
Timestamp: 2026-02-24T05:52:50.560Z
Learning: In WeGo_FrontEnd repository: Server state (e.g., unReadCount from API) should be managed only by React Query, not stored in Zustand global state. Each component calls the API but uses cached data from React Query. Principle: "서버상태는 React Query 로만 관리한다" (Server state managed only by React Query).

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그 부분은 명확하게 이해하고 있고, 해당 부분 자체가 삭제될 예정이기 때문에 말씀드렸습니다

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Chiman2937, 알겠습니다! 해당 코드가 후속 PR에서 삭제될 예정이라면 지금 수정할 필요가 없네요. 말씀해주셔서 감사합니다. 👍


🧠 Learnings used
Learnt from: Chiman2937
Repo: WeGo-Together/WeGo_FrontEnd PR: 393
File: src/hooks/use-notification/use-notification-get-unread-count/index.ts:5-5
Timestamp: 2026-02-24T05:52:50.560Z
Learning: In the WeGo_FrontEnd repository, server state (e.g., unread counts from APIs) must be managed exclusively by React Query and not stored in Zustand or other client state. Components may call the API but should rely on React Query's cache for rendering. Apply this guideline to all hook implementations that deal with server state; avoid writing server-state data to Zustand and prefer React Query data selectors or hooks to access cached results.

@Chiman2937 Chiman2937 merged commit 6d468b6 into main Feb 24, 2026
9 checks passed
@Chiman2937 Chiman2937 deleted the chiyoung-refactor/auth-state branch February 24, 2026 05:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant