Files
a301_client/src/pages/SSAFYCallbackPage.jsx
tolelom 1a3be5f76b
All checks were successful
Client CI/CD / test (push) Successful in 12s
Client CI/CD / deploy (push) Successful in 38s
fix: ESLint react-hooks 최신 규칙 호환
- useCallback → 일반 함수 + eslint-disable (초기 데이터 fetch)
- ToastProvider: useCallback 프로퍼티 할당 → useMemo 객체 패턴
- SSAFYCallbackPage: eslint-disable-line 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 23:45:10 +09:00

54 lines
1.8 KiB
JavaScript

import { useEffect, useState, useRef } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { useAuth } from '../context/useAuth';
import { ssafyCallback } from '../api/auth';
// Inline styles are intentional for this simple callback/loading page — not worth a separate CSS file.
export default function SSAFYCallbackPage() {
const [error, setError] = useState('');
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const { setUserFromSSAFY } = useAuth();
// useRef(false) prevents double-execution in React 18+ StrictMode,
// which remounts components in development. The ref persists across
// the StrictMode remount, ensuring the OAuth callback runs only once.
const called = useRef(false);
useEffect(() => {
if (called.current) return;
called.current = true;
const code = searchParams.get('code');
if (!code) {
setError('인가 코드가 없습니다.'); // eslint-disable-line react-hooks/set-state-in-effect -- error state from URL param check
return;
}
ssafyCallback(code)
.then((data) => {
setUserFromSSAFY(data);
navigate('/', { replace: true });
})
.catch((err) => {
setError(err.message || 'SSAFY 로그인에 실패했습니다.');
});
}, [searchParams, setUserFromSSAFY, navigate]);
if (error) {
return (
<div style={{ textAlign: 'center', marginTop: '4rem' }}>
<p style={{ color: '#e74c3c' }}>{error}</p>
<button onClick={() => navigate('/login', { replace: true })}>
로그인 페이지로 돌아가기
</button>
</div>
);
}
return (
<div style={{ textAlign: 'center', marginTop: '4rem' }}>
<p>SSAFY 로그인 처리 ...</p>
</div>
);
}