임동욱 임동욱 08-11
fix: LogoutNotice 토스트 중복 표시 방지
개발 모드 Strict Mode(App Router 기본값)의 effect mount→cleanup→remount 2회 호출로
쿼리 파라미터 감지 토스트가 두 번 뜨는 것을 실제 브라우저 검증 중 확인했다. cleanup 없는
effect라 가드가 없으면 매 remount마다 showToast가 재실행된다. hasNotifiedRef로 최초
1회만 실행되도록 고정한다 — 사용자에게 보이는 알림은 Strict Mode 유무와 무관하게 항상
1회여야 한다.

Co-Authored-By: Claude Opus 5 
@3861060af26628a1374b141d93654f76ed3de2b6
app/(public)/login/_components/logout-notice.tsx
--- app/(public)/login/_components/logout-notice.tsx
+++ app/(public)/login/_components/logout-notice.tsx
@@ -1,6 +1,6 @@
 'use client';
 
-import { useEffect } from 'react';
+import { useEffect, useRef } from 'react';
 import { useRouter } from 'next/navigation';
 import { useFeedback } from '@/app/_hooks/use-feedback';
 
@@ -23,15 +23,24 @@
  *
  * 표시 후에는 쿼리 파라미터를 제거한다(router.replace) — 새로고침·북마크 재방문 시 지난 실패가
  * 다시 뜨는 것을 막는다.
+ *
+ * `hasNotifiedRef`로 실행을 1회로 못박는다 — App Router는 기본 Strict Mode(next.config.ts에
+ * 별도 설정이 없으면 true, Next.js 13.5.1부터 기본값)라 개발 모드에서 effect가 mount→cleanup→
+ * remount로 2회 호출된다. 이 effect엔 cleanup이 없어 가드가 없으면 토스트가 두 번 뜬다 —
+ * router.replace가 아직 반영되기 전(같은 커밋 내)에 두 번째 호출이 일어나 showError prop이
+ * 그대로 true이기 때문이다. 프로덕션은 원래 1회지만, 사용자에게 실제로 보이는 부수효과(알림)는
+ * Strict Mode 유무와 무관하게 항상 1회여야 한다.
  */
 export function LogoutNotice({ showError }: LogoutNoticeProps) {
   const router = useRouter();
   const { showToast } = useFeedback();
+  const hasNotifiedRef = useRef(false);
 
   useEffect(() => {
-    if (!showError) {
+    if (!showError || hasNotifiedRef.current) {
       return;
     }
+    hasNotifiedRef.current = true;
 
     // 내부 정보(백엔드 message 원문 등)는 노출하지 않는다 — 항상 이 고정 문구만 보여준다.
     showToast({ variant: 'warning', message: LOGOUT_ERROR_MESSAGE });
Add a comment
List