Conversation
|
""" Walkthrough이번 변경사항은 인증 및 사용자 정보 관리 로직의 대대적인 리팩토링과 신규 인증 콜백 플로우 도입, 그리고 사용자 정보 API 및 관련 커스텀 훅 추가에 초점을 맞추고 있습니다. 인증 저장소(authStore)는 토큰 기반에서 로그인 상태 플래그와 사용자 이름 기반으로 단순화되었으며, 인증 콜백을 처리하는 신규 라우트와 컴포넌트가 추가되었습니다. 사용자 정보 조회 및 갱신을 위한 API와 타입, 커스텀 React 훅이 신설되었고, 기존의 일부 페이지들은 이 구조에 맞게 데이터 흐름과 상태 관리를 변경하였습니다. 또한, axios 클라이언트의 API base URL이 환경 변수 기반으로 변경되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant AuthCallbackPage
participant AuthStore
participant UserAPI
participant Router
User->>AuthCallbackPage: 인증 콜백 URL 접근 (status 쿼리 포함)
AuthCallbackPage->>AuthStore: login() 호출
AuthCallbackPage->>UserAPI: readUser() 호출
UserAPI-->>AuthCallbackPage: 사용자 정보 반환
AuthCallbackPage->>AuthStore: setName(이름) 호출
AuthCallbackPage-->>Router: (조건부) 페이지 이동
sequenceDiagram
participant InfoInputPage
participant useUserInfo
participant useUserUpdate
participant UserAPI
InfoInputPage->>useUserInfo: 사용자 정보 쿼리
useUserInfo->>UserAPI: readUser()
UserAPI-->>useUserInfo: 사용자 정보 반환
useUserInfo-->>InfoInputPage: 데이터 전달
InfoInputPage->>useUserUpdate: updateUser(수정 데이터)
useUserUpdate->>UserAPI: updateUser()
UserAPI-->>useUserUpdate: 갱신 결과 반환
useUserUpdate-->>InfoInputPage: 결과/에러 콜백
Possibly related PRs
Suggested reviewers
Poem
""" 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (3)
src/features/join/model/userInformation.ts (1)
8-13: 사용자 정보 요청 타입 정의사용자 정보 요청을 위한 인터페이스가 응답 인터페이스와 동일한 구조로 정의되었습니다. 현재는 동일하지만, 향후 요청과 응답 구조가 다를 경우를 대비한 좋은 접근법입니다.
이 두 인터페이스가 현재 동일한 구조인 경우 타입 별칭을 사용하는 것도 고려해볼 수 있습니다:
+type UserInfo = { + id: number; + name: string; + phoneNumber: string; + email: string; +} + +export type UserInfoResponse = UserInfo; +export type UserInfoRequest = UserInfo;src/features/join/hooks/useUserHook.ts (2)
5-10: React Query 훅 구현이 좋습니다만 몇 가지 개선이 가능합니다.useUserInfo 훅이 잘 구현되어 있습니다. 그러나 staleTime, cacheTime 또는 재시도 로직과 같은 구성 옵션이 없습니다.
데이터 로딩 상태를 더 효율적으로 관리하기 위해 추가 옵션을 고려해보세요:
export const useUserInfo = () => { return useQuery<UserInfoResponse>({ queryKey: ['userInfo'], queryFn: readUser, + staleTime: 5 * 60 * 1000, // 5분 + cacheTime: 10 * 60 * 1000, // 10분 + retry: 1, + refetchOnWindowFocus: false, }); };
12-16: useMutation 훅이 성공/오류 콜백을 처리하기 위한 옵션이 부족합니다.useUserUpdate 훅이 기본 기능은 제공하지만, 소비 컴포넌트가 일관된 방식으로 성공 및 오류 처리를 할 수 있도록 도움이 되는 기능이 없습니다.
useMutation에 기본 콜백을 추가하거나 onSettled 핸들러를 제공하는 것이 좋습니다:
export const useUserUpdate = () => { return useMutation<UserInfoResponse, Error, UserInfoRequest>({ mutationFn: updateUser, + onError: (error) => { + console.error('사용자 정보 업데이트 오류:', error); + }, + onSettled: () => { + // 쿼리 캐시 무효화 또는 업데이트 + queryClient.invalidateQueries(['userInfo']); + } }); }이를 위해서는 상단에 다음을 추가해야 합니다:
import { QueryClient, useMutation, useQuery } from '@tanstack/react-query'; const queryClient = new QueryClient(); // 또는 외부 QueryClient 인스턴스 사용
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
src/app/provider/authStore.ts(2 hunks)src/app/routes/Router.tsx(2 hunks)src/app/routes/routes.ts(1 hunks)src/features/join/api/user.ts(1 hunks)src/features/join/hooks/useUserHook.ts(1 hunks)src/features/join/model/userInformation.ts(1 hunks)src/pages/event/ui/EventDetailsPage.tsx(1 hunks)src/pages/home/ui/MainPage.tsx(3 hunks)src/pages/join/AuthCallback.tsx(1 hunks)src/pages/join/InfoInputPage.tsx(5 hunks)src/pages/menu/ui/MyTicketPage.tsx(1 hunks)src/shared/types/api/http-client.ts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/features/join/api/user.ts (2)
src/features/join/model/userInformation.ts (2)
UserInfoResponse(1-6)UserInfoRequest(8-13)src/shared/types/api/http-client.ts (1)
axiosClient(6-13)
src/app/routes/Router.tsx (1)
src/app/routes/routes.ts (1)
JOIN_ROUTES(16-21)
src/pages/home/ui/MainPage.tsx (1)
src/app/provider/authStore.ts (1)
useAuthStore(17-33)
src/features/join/hooks/useUserHook.ts (2)
src/features/join/model/userInformation.ts (2)
UserInfoResponse(1-6)UserInfoRequest(8-13)src/features/join/api/user.ts (2)
readUser(4-7)updateUser(9-12)
🔇 Additional comments (13)
src/shared/types/api/http-client.ts (2)
7-7: 환경 변수를 사용한 API 기본 URL 설정 개선하드코딩된 URL에서 환경 변수를 사용하는 방식으로 변경한 것은 좋은 접근입니다. 이는 다양한 환경(개발, 스테이징, 프로덕션)에 맞게 쉽게 URL을 구성할 수 있게 해줍니다.
15-22:Details
❓ Verification inconclusive
인증 토큰 처리 로직 제거에 따른 검증 필요
요청 인터셉터에서 토큰 처리 로직이 제거되었습니다. 이는 authStore 리팩토링과 일치하는 변경이지만, 인증이 필요한 API 요청이 여전히 제대로 작동하는지 확인해야 합니다.
다음 스크립트를 실행하여 인증이 필요한 API 요청 패턴을 확인하세요:
인증이 필요한 엔드포인트에 헤더가 어떻게 설정되고 있는지 확인하고, 인증 흐름이 제대로 작동하는지 테스트해보세요.
🏁 Script executed:
#!/bin/bash # API 호출 패턴 확인하기 rg -A 3 -B 3 "axiosClient\.(get|post|put|delete)" --type=tsLength of output: 9296
인증 토큰 처리 로직이 다른 곳으로 이동했는지 확인하기 위해 다음 스크립트를 실행해주세요.
🏁 Script executed:
#!/bin/bash # axiosClient 설정 및 인증 토큰 처리 확인 echo "----- src/shared/types/api/http-client.ts (상단) -----" sed -n '1,200p' src/shared/types/api/http-client.ts echo "----- authStore 사용 위치 검색 -----" rg -C3 "authStore" --type ts echo "----- getAccessToken 또는 비슷한 함수 검색 -----" rg -C3 "getAccessToken" --type ts echo "----- axiosClient.defaults.headers 검색 -----" rg -C3 "defaults.headers" --type ts echo "----- Authorization 헤더 직접 설정 검색 -----" rg -i -C3 "authorization" --type tsLength of output: 5475
쿠키 기반 인증(withCredentials) 전환 후 검증 필요
src/shared/types/api/http-client.ts에서 요청 인터셉터의Authorization헤더 주입 로직이 삭제되고, 대신withCredentials: true를 사용해 쿠키 기반 인증으로 변경된 것으로 보입니다. 이 변경이 백엔드에서 의도한 대로 작동하는지 아래 항목을 확인해주세요.
- 브라우저 요청에
access_token쿠키가 포함되어 인증 API 호출이 정상 처리되는지- 401 응답 발생 시
js-cookie로 쿠키가 제거되고useAuthStore.getState().openModal()이 호출되어 로그인 모달이 제대로 뜨는지- S3 프리사인드 URL 업로드 시
delete axiosClient.defaults.headers.common.Authorization로직이 필요하거나 의도대로 동작하는지src/app/provider/authStore.ts (1)
4-15: 인증 저장소 인터페이스 단순화 개선토큰 기반 관리에서 로그인 상태 플래그와 사용자 이름 기반으로 단순화한 것은 좋은 접근입니다. 이는 상태 관리를 더 간결하게 만들고 유지보수성을 향상시킵니다.
src/pages/menu/ui/MyTicketPage.tsx (1)
35-35: 토큰 동기화 로직 제거토큰 동기화 로직이 제거된 것은 authStore 리팩토링과 일치하며, 인증 관리 방식을 단순화하는 좋은 변경입니다. 이제 쿠키에서 토큰을 읽어 저장소에 설정하는 로직 대신 isLoggedIn 플래그를 사용합니다.
다만, 사용자 티켓 정보를 가져오는 API 호출(readTicket.getAll)에 인증이 필요한 경우, 인증 처리가 제대로 이루어지는지 확인이 필요합니다. 현재 인증 헤더 설정 로직이 http-client.ts에서 제거되었기 때문입니다.
src/pages/home/ui/MainPage.tsx (2)
34-34: 인증 상태 관리 개선됨
useAuthStore에서isLoggedIn과name을 추가로 구조 분해하여 사용자 로그인 상태와 이름을 활용할 수 있게 되었습니다. 이는 토큰 기반 인증에서 상태 플래그 기반 인증으로의 리팩토링을 반영합니다.
60-60: 사용자 경험 개선로그인 상태에 따라 버튼 레이블이 동적으로 변경되어 사용자에게 개인화된 경험을 제공합니다. 로그인한 사용자에게는 이름과 함께 "님"을 표시하고, 로그인하지 않은 사용자에게는 "로그인"을 표시합니다.
src/app/routes/routes.ts (1)
20-20: 소셜 로그인 콜백 경로 추가소셜 로그인 프로세스 완료 후 리다이렉션을 처리하기 위한 인증 콜백 경로가 추가되었습니다. 이 경로는 OAuth 인증 흐름에서 중요한 부분입니다.
src/app/routes/Router.tsx (2)
37-37: AuthCallback 컴포넌트 임포트소셜 로그인 콜백을 처리하기 위한 새로운 컴포넌트를 임포트했습니다. 이 컴포넌트는 인증 프로세스 완료 후 사용자 정보를 처리할 것으로 예상됩니다.
52-52: 인증 콜백 라우트 구성 추가소셜 로그인 후 리디렉션을 처리하기 위한 콜백 라우트가 적절하게 구성되었습니다. 인증이 필요하지 않은 페이지로 올바르게 설정되어 있어 인증 흐름이 제대로 작동할 수 있습니다.
src/features/join/model/userInformation.ts (1)
1-6: 사용자 정보 응답 타입 정의사용자 정보 응답을 위한 인터페이스가 적절하게 정의되었습니다. 기본적인 사용자 식별자와 개인 정보(이름, 전화번호, 이메일)를 포함하고 있습니다.
src/pages/join/AuthCallback.tsx (1)
18-19: 주석 처리된 navigate 코드가 있습니다.코드에 주석 처리된 navigate 호출이 있는데, 이는 미완성 기능이나 진행 중인 작업을 나타냅니다.
이 주석 처리된 코드의 목적을 확인하고 적절하게 구현하거나 제거해야 합니다. 만약 일부러 비활성화 한 것이라면 이유를 주석으로 명시하는 것이 좋습니다.
if (status === 'new') { - //navigate('/join/agreement'); + // TODO: 합의 페이지로 이동하는 기능 구현 예정 + // navigate('/join/agreement'); } else { setName(data?.name || "사용자"); console.log(isModalOpen); - //navigate('/'); + // TODO: 홈페이지로 리디렉션 기능 구현 예정 + // navigate('/'); }Also applies to: 22-23
src/pages/join/InfoInputPage.tsx (2)
10-11: 로딩 상태 처리가 개선되었습니다.useUserInfo 훅의 isLoading 상태를 확인하고 로딩 상태를 표시하는 것은 좋은 사용자 경험을 제공합니다.
로딩 상태 처리가 적절하게 구현되어 있습니다. 이는 데이터가 로드되기 전에 사용자에게 피드백을 제공하는 좋은 방법입니다.
Also applies to: 58-60
32-48: updateUser 콜백 처리가 잘 구현되어 있습니다.mutation 함수를 사용하여 사용자 정보를 업데이트하고 성공 및 오류 콜백을 처리하는 방식이 잘 구현되어 있습니다.
성공 및 오류 상태에 대한 명확한 피드백과 적절한 내비게이션이 구현되어 있습니다. 사용자 경험을 위한 좋은 처리 방식입니다.
|
|
||
| const [event, setEvent] = useState<ReadEvent | null>(null); | ||
| const eventId = 1; //수정 필요 | ||
| const eventId = 21; //수정 필요 |
There was a problem hiding this comment.
하드코딩된 이벤트 ID에 대한 수정 필요
현재 이벤트 ID가 하드코딩되어 있고 주석에도 '수정 필요'라고 표시되어 있습니다. 실제 프로덕션 환경에서는 URL 파라미터나 상태 관리를 통해 동적으로 eventId를 받아오는 것이 좋습니다.
다음과 같이 URL에서 동적으로 ID를 받아오는 방식을 고려해보세요:
- const eventId = 21; //수정 필요
+ const { eventId } = useParams<{ eventId: string }>();
+ const numericEventId = eventId ? parseInt(eventId, 10) : undefined;이 경우 Router 설정도 수정해야 합니다. 또한 API 호출 시 eventId가 undefined일 경우의 예외 처리도 필요합니다.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/shared/types/api/http-client.ts (1)
43-59: 토큰 갱신 로직 구현 완료토큰 만료 시 자동으로 갱신하는 로직이 잘 구현되었습니다. 그러나 토큰 재시도 메커니즘을 개선하기 위해 몇 가지 제안사항이 있습니다:
- 무한 재시도 루프를 방지하기 위한 재시도 플래그 추가
- 재시도 횟수 제한 설정
다음과 같이 개선할 수 있습니다:
async (error: AxiosError<ApiErrorResponse>) => { const errorInfo = { status: error.response?.status || 'NETWORK_ERROR', message: error.response?.data?.message || error.message, }; - const originalRequest = error.config as any; + const originalRequest = error.config as AxiosRequestConfig & { _retry?: boolean }; // 401(토큰 만료)일 경우 로그아웃 처리 or 토큰 갱신 가능 if (errorInfo.status === 401) { + // 이미 재시도한 요청인 경우 더 이상 재시도하지 않음 + if (originalRequest._retry) { + Cookies.remove('access_token'); + useAuthStore.getState().openModal(); + return Promise.reject(errorInfo); + } + + // 재시도 플래그 설정 + originalRequest._retry = true; + try { await axios.post( `${import.meta.env.VITE_API_BASE_URL}/api/v1/auth/refresh`, {}, { withCredentials: true, } ); // 새 토큰이 쿠키에 재설정되었으므로 원래 요청 재시도 return axiosClient(originalRequest); } catch (refreshError) { // 리프레시 실패 시 로그아웃 처리 Cookies.remove('access_token'); useAuthStore.getState().openModal(); - return Promise.reject(refreshError); + return Promise.reject(errorInfo); } }src/pages/join/LogoutPage.tsx (1)
5-22: 로그아웃 페이지 구현 완료, 사용자 경험 개선 필요로그아웃 기능이 기본적으로 잘 구현되어 있지만, 사용자 경험을 개선할 수 있는 몇 가지 제안사항이 있습니다:
- 로딩 상태 표시 추가
- 더 친절한 에러 메시지 제공
- 로그아웃 성공/실패 시 시각적 피드백 추가
다음과 같이 개선할 수 있습니다:
import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { axiosClient } from '../../shared/types/api/http-client'; +import useAuthStore from '../../../app/provider/authStore'; const LogoutPage = () => { const navigate = useNavigate(); + const { logout } = useAuthStore(); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState<string | null>(null); useEffect(() => { const logoutProcess = async () => { + setIsLoading(true); try { await axiosClient.post('/oauth/logout'); + logout(); // 클라이언트 상태 정리 navigate('/'); } catch (error) { console.error('로그아웃 실패:', error); - alert('로그아웃에 실패했습니다. 다시 시도해주세요.'); + setError('로그아웃에 실패했습니다. 네트워크 연결을 확인하고 다시 시도해주세요.'); + setIsLoading(false); } }; - logout(); + logoutProcess(); }, [navigate]); - return <div>로그아웃 중...</div>; + if (isLoading) { + return <div className="logout-loading">로그아웃 중...</div>; + } + + if (error) { + return ( + <div className="logout-error"> + <p>{error}</p> + <button onClick={() => window.location.reload()}>다시 시도</button> + </div> + ); + } + + return null; // 로딩 중이거나 에러가 없으면 렌더링할 필요 없음 (리다이렉트 됨) }; export default LogoutPage;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
.github/workflows/storybook.yml(1 hunks)src/app/provider/authStore.ts(2 hunks)src/app/routes/Router.tsx(3 hunks)src/app/routes/routes.ts(2 hunks)src/pages/home/ui/MainPage.tsx(3 hunks)src/pages/join/AuthCallback.tsx(1 hunks)src/pages/join/InfoInputPage.tsx(2 hunks)src/pages/join/LogoutPage.tsx(1 hunks)src/shared/lib/formValidation.ts(1 hunks)src/shared/types/api/http-client.ts(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- .github/workflows/storybook.yml
🚧 Files skipped from review as they are similar to previous changes (6)
- src/pages/home/ui/MainPage.tsx
- src/app/routes/Router.tsx
- src/app/routes/routes.ts
- src/pages/join/InfoInputPage.tsx
- src/pages/join/AuthCallback.tsx
- src/app/provider/authStore.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/pages/join/LogoutPage.tsx (1)
src/shared/types/api/http-client.ts (1)
axiosClient(6-13)
src/shared/types/api/http-client.ts (2)
src/shared/types/api/apiResponse.ts (1)
ApiErrorResponse(7-9)src/app/provider/authStore.ts (1)
useAuthStore(17-33)
🪛 ESLint
src/shared/types/api/http-client.ts
[error] 39-39: Unexpected any. Specify a different type.
(@typescript-eslint/no-explicit-any)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: storybook
🔇 Additional comments (5)
src/shared/lib/formValidation.ts (1)
10-13:Details
❓ Verification inconclusive
전화번호 유효성 검사 규칙이 개선되었습니다.
새로운 전화번호 유효성 검사는 하이픈(-)을 포함한 형식으로 강제하여 데이터의 일관성을 높이고 가독성을 개선했습니다. 또한 .min(1) 검사를 추가하여 전화번호가 비어있지 않도록 보장했습니다.
이 패턴은 한국 전화번호 형식(XXX-XXX(X)-XXXX)에 최적화되어 있습니다.
전화번호 입력 시 사용자가 직접 하이픈을 입력해야 하나요? 입력 컴포넌트에서 자동 포맷팅 기능을 제공하는지 확인해주세요. 사용자 경험을 향상시키기 위해 입력 필드에 자동 포맷팅이나 마스크 기능을 고려해보세요.
🏁 Script executed:
#!/bin/bash # 전화번호 입력 관련 컴포넌트 찾기 rg -A 5 -B 5 "phone|Phone|전화" --type tsxLength of output: 70
전화번호 입력 컴포넷의 자동 포맷팅 기능 확인 필요
src/shared/lib/formValidation.ts에서 하이픈(-) 포함 형식을 강제하고.min(1)을 추가해 빈 입력을 방지한 유효성 검사 규칙이 잘 반영되었습니다.- 사용자 경험을 위해, 실제 입력 컴포넌트가 하이픈을 자동 삽입하거나 마스크 기능을 제공하는지 확인해주세요.
- 자동 포맷팅 기능이 없다면,
react-input-mask같은 라이브러리 도입 또는 커스텀 마스크 구현을 고려해보시기 바랍니다.src/shared/types/api/http-client.ts (2)
7-7: 환경 변수를 사용한 API 기본 URL 설정 개선됨하드코딩된 문자열 대신 환경 변수(
import.meta.env.VITE_API_BASE_URL)를 사용하여 baseURL을 설정한 것은 좋은 변경입니다. 이렇게 하면 개발, 테스트, 프로덕션 환경 간에 쉽게 URL을 전환할 수 있습니다.
56-56:Details
✅ Verification successful
컴포넌트 외부에서 스토어 직접 접근 방식 검토 필요
useAuthStore.getState().openModal()은 컴포넌트 외부에서 스토어에 직접 접근하는 방식으로, React 컴포넌트 패턴과 완전히 일치하지 않습니다. 하지만 인터셉터 내에서는 이 방식이 적절할 수 있습니다.참고: React 컴포넌트에서는 일반적으로 훅을 직접 사용하는 것이 권장되지만, 컴포넌트 외부의 유틸리티 함수나 인터셉터에서는
getState()를 통한 직접 접근이 필요합니다. Zustand 문서에서 이 패턴의 적절성을 확인해보세요.
🌐 Web query:
Zustand React store access outside component💡 Result:
Accessing Zustand Store Outside React Components
You can access and manipulate your Zustand store outside React components by leveraging its design, which exposes methods for reading and writing state independently of React's lifecycle.
Direct Access with
.getState()and.setState()Once you've defined your Zustand store, you can access its state and actions in any JavaScript file (e.g., utilities, API handlers, or server code), not just inside React components. This is possible because the store returned by
createis more than just a hook — it also exposes helper methods:import { create } from 'zustand'; const useStore = create((set) => ({ bears: 0, increase: () => set((state) => ({ bears: state.bears + 1 })), })); // Outside React components: const { getState, setState } = useStore; // Read state console.log(getState().bears); // Modify state setState({ bears: 10 }); // Call actions getState().increase();This pattern works well for situations such as logging, integrating with non-React code, or testing[5].
Using Vanilla Stores for Non-React Environments
For advanced use cases—like when you need to share store logic between React and non-React environments—consider using Zustand's "vanilla" store. Import
createStorefromzustand/vanilla, which creates a store object independent of React:import { createStore } from 'zustand/vanilla'; const appContextStore = createStore((set) => ({ clientURL: '', setClientURL: (clientURL) => set({ clientURL }), firstLoad: true, setFirstLoad: (firstLoad) => set({ firstLoad }), })); export default appContextStore;You can access and modify state through
appContextStore.getState()andappContextStore.setState(). If you want React components to reactively use this vanilla store, you can connect it using theuseStorehook by passing the store instance as an argument[1][3].Caveats & Best Practices
- Reactivity: Reading state with
getState()outside React will not trigger re-renders in React components. Use the hook inside components for reactive updates.- Batched Updates: When updating the state from outside React (especially before React 18), you might need to batch updates to avoid unexpected re-renders. Wrap external actions in
unstable_batchedUpdatesif you notice issues[4].- Consistency: Using the same store instance everywhere ensures consistency. If you combine vanilla stores with React context, ensure you're always referencing the same store object to avoid desynchronization[3].
Summary Table
Access Pattern Usage Context Reactive in Components? useStore((state) => state.value)Inside React components Yes useStore.getState()/useStore.setState()Outside React (any JS file) No (state is updated, no re-render) createStorefromzustand/vanillaNon-React or hybrid environments Use with useStore(store, selector)Zustand's flexibility means you can use its store seamlessly both inside and outside React components, making it a powerful choice for state management needs[5][1][3].
Citations:
- 1: pmndrs/zustand#1204
- 2: https://github.com/pmndrs/zustand
- 3: https://tkdodo.eu/blog/zustand-and-react-context
- 4: https://zustand.docs.pmnd.rs/guides/event-handler-in-pre-react-18
- 5: https://dev.to/ricardogesteves/zustand-when-how-and-why-1kpi
- 6: https://refine.dev/blog/zustand-react-state/
getState()를 통한 컴포넌트 외부 접근 패턴은 적절합니다인터셉터나 비-React 유틸리티 함수 내에서
useAuthStore.getState().openModal();와 같이 Zustand 스토어에 직접 접근하는 방식은 Zustand 공식 문서에서도 권장하는 패턴입니다.
React 컴포넌트 내부에서는 훅(useAuthStore(selector))을 사용해 반응성을 유지해야 하지만, 컴포넌트 외부 로직에서는getState()/setState()를 이용해 상태를 조회·조작하는 것이 올바른 접근입니다.추가 조치가 필요하지 않습니다.
src/pages/join/LogoutPage.tsx (2)
1-4: import 문 구조 적절함필요한 의존성을 명확하게 가져오고 있으며, 불필요한 import가 없어 깔끔합니다.
11-11:Details
❓ Verification inconclusive
API 엔드포인트 경로 검증 필요
로그아웃 요청을
/oauth/logout엔드포인트로 보내고 있습니다. 이 경로가 백엔드 API와 일치하는지 확인해주세요.
🏁 Script executed:
#!/bin/bash # API 엔드포인트 경로 검증 # axiosClient 설정과 함께 엔드포인트 검색 echo "백엔드 API 엔드포인트 검증 중..." grep -r "/oauth/logout" --include="*.ts" --include="*.tsx" . grep -r "logout" --include="*.ts" --include="*.tsx" . | grep -v "LogoutPage.tsx"Length of output: 715
/oauth/logoutAPI 경로 백엔드 일치 여부 확인 필요
- src/pages/join/LogoutPage.tsx (11번 줄):
await axiosClient.post('/oauth/logout');- 현재 코드베이스에서 해당 엔드포인트 호출은 이 한 곳뿐이며, 백엔드 API 정의와 정확히 일치하는지 확인 후 필요하면 경로를 수정해주세요.
소셜 로그인 구현 - 카카오 & 구글
카카오 로그인
구글 로그인
신규 로그인 시 이용약관 동의 페이지로 이동
이름, 이메일은 자동으로 불러오고 전화번호만 입력받음.
전화번호 입력 형식 변경
Summary by CodeRabbit
신규 기능
버그 수정
리팩터
스타일/UX
기타