feat: 5주차 첫번째 미션 - #51
Conversation
1주차 미션1 - 뮤
Feat: 2주차 미션1 - 뮤
Feat: 2주차 미션2 - 뮤
Feat: Week3/nonshaman m2
Revert "Feat: Week3/nonshaman m2"
yewon20804
left a comment
There was a problem hiding this comment.
전체적으로 useBallAnimation 훅 분리 등 저번 미션에서 구조적으로 수정해주셨는데요 ! 다만 이번 미션의 핵심인 Context API를 통한 전역 인증 상태 관리가 빠져 있어서, 이 부분을 포함해서 코멘트 남깁니다
AuthContext 없이 localStorage를 직접 참조하고 있습니다
이번 미션의 목표는 Context API로 인증 상태를 전역 관리하는 것입니다. 현재는 ProtectedRoute, MyPage, LoginPage 등 여러 컴포넌트에서 매번 localStorage.getItem('accessToken')을 직접 호출하고 있습니다.
이렇게 작성되면 토큰이 삭제되거나 변경되어도 컴포넌트가 자동으로 리렌더되지 않아 변경된 내용을 모릅니다 ! 예를 들어 handleLogout에서 localStorage를 삭제해도 다른 컴포넌트는 즉시 반응하지 않습니다. 그래서 로그인/로그아웃 로직이 여러 곳에 분산되어 유지보수가 어려워집니다
아래와 같이 AuthContext를 만들어 관리하는 것을 권장해요:
// src/context/AuthContext.tsx 를 만들어서 전역으로 관리하는 방법을 좀더 고민해보세요 !
ProtectedRoute에서 렌더링 중 alert() 호출
// 현재 코드
if (!isLogin) {
alert('로그인이 필요한 페이지입니다!');
return <Navigate to="/login" replace />;
}
alert()은 렌더링 과정 안에서 실행하면 안 되는 side effect입니다.
React에서는 렌더링은 UI만 그려야 하고, alert 같은 동작은 useEffect에서 처리해야 합니다 !
그래서 useEffect로 분리해서 처리하는 것이 더 안전한 방식입니다.
// 개선 — useEffect 처리 예시
const ProtectedRoute = () => {
const { isAuthenticated } = useAuthContext(); // 1번 내용을 반영했다는 가정 하에
useEffect(() => {
if (!isAuthenticated) {
alert('로그인이 필요한 페이지입니다!');
}
}, [isAuthenticated]);
if (!isAuthenticated) return <Navigate to="/login" replace />;
return <Outlet />;
};
API 호출마다 토큰을 수동으로 붙이지 말고 interceptor를 활용
MyPage.tsx에서 API 호출 시마다 토큰을 직접 꺼내서 헤더에 붙이고 있습니다
// 현재
const token = localStorage.getItem('accessToken');
const response = await api.get('/users/me', {
headers: { Authorization: `Bearer ${token}` }
});
src/apis/axios.ts에 request interceptor를 추가하면, 이후 모든 API 호출에서 토큰이 자동으로 첨부가 가능하여 인증이 필요한 API가 늘어날수록 이 방식이 훨씬 유지보수하기 좋습니다 !
// 개선
const api = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000/v1',
});
api.interceptors.request.use((config) => {
const token = localStorage.getItem('accessToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
export default api;
이렇게 설정하면 MyPage에서는 그냥 api.get('/users/me')로만 호출하면 됩니다.
코멘트 확인해주시고, 해당 내용들 반응하면 더 완벽하게 마무리할 수 있을 것 같습니다 👍
그리고 다음 PR에서는 화면 스크린샷 첨부해주시면 더 꼼꼼하게 확인해드릴게용 !
📚 주차 / 미션
📌 작업 내용
✨ 상세 작업 내용
📸 스크린샷
❓ 리뷰어가 알아야 할 사항 / 질문
✅ 체크리스트