오늘도 일단 해결한 내용을 복습겸 적어 보겠다.
해결하기 전 기록은 없으니 이렇게라도 적어두기.
일단 전체적인 흐름은
[1. 로그인 → 2. 서버로 데이터 전송 → 3. JWT 토큰 및 기타 데이터 반환 → 4. 프론트에서 받아서 decoding(토큰 복호화) → 5. 토큰 데이터를 이용하여 프론트에서 사용하기] 순서이다.
오늘 문제가 됐던 건, 4~5 번 사이에서 발생되었다.
로그인 하면 토큰이 반환되고, 메인 화면으로 이동하는데 그때 토큰은 들어 있지만, 새로고침을 하는 순간 토큰 정보가 없어지는 문제였다.
<최초 로그인 로직>
const onClickLoginHandler = async () => {
const isLoginSuccess = await dispatch(callLoginAPI({ form }));
if (isLoginSuccess) {
console.log('isLoginSuccess : ', isLoginSuccess);
// 로그인 하고 decoding 해야 함.
const token = decodeJwt(window.localStorage.getItem("accessToken"));
console.log('token : ', token);
console.log('token.sub : ', token.sub);
if(token){
dispatch(callGetMemberAPI({memberId : token.sub}));
navigate("/");
} else {
console.error("유효하지 않은 토큰!!");
}
}
}
(다행히 이건 주석 처리를 해놔서 가져옴) (어제 로그인 연결하고 좋아했었는데....)
크게 로그인 클릭 시 callLoginAPI가 발동되어 서버의 데이터를 가져오고 토큰을 복호화하여 token에 담고,
다시 dipatch로 callGetMemberAPI를 호출하여 스토어에 저장하는 흐름이었다.
이렇게 하면 로그인 후 최초, 토큰 데이터는 확인 가능하지만 새로고침하면 날라간다.
로그인 한 회원의 토큰 정보가 남아 있어야 뭐든 할 수 있는데 참 고민이었다.
이것저것 찾아봤는데 persistReducer를 사용하면 문제가 해결된다고 하더라....
하지만 뭔가 더 간단한 방법을 찾았다. (저건 나중에 사용해 보기로)
해결 방법으로는 최상단 컴포넌트인 APP에 토큰을 가져다 놓는 것이다.
모든 컴포넌트는 App 하위에 있으니, 최상단에 토큰 정보를 저장해 두면 되지 않을까 했다.
import { Routes, Route } from 'react-router-dom';
import UserLayout from './layouts/UserLayout';
import OwnerLayout from './layouts/OwnerLayout';
import AdminLayout from './layouts/AdminLayout';
import Main from './pages/common/Main'
import MyPage from './pages/user/MyPage';
import OwnerMyPage from './pages/owner/OwnerMyPage';
import Test from './pages/Test';
import Rental from './pages/admin/Rental';
import AuthorityLayout from './layouts/AuthorityLayout';
import AdminMain from './pages/admin/AdminMain';
import AdminUser from './pages/admin/AdminUser';
import ListPage from './pages/common/ListPage';
import { useEffect, useState } from 'react';
import Login from './pages/login/Login';
import Signup from './pages/login/Singup';
import OwnerProducts from './pages/owner/OwnerProducts';
import AdminProduct from './pages/admin/AdminProduct';
import Inquiry from './pages/user/Inquiry';
import Orders from './pages/user/Orders';
import { useDispatch, useSelector } from 'react-redux';
import { callGetMemberAPI } from './apis/MemberAPI';
import decodeJwt from './utils/tokenUtils';
import OwnerRegister from './pages/owner/OwnerRegister';
function App() {
const token = decodeJwt(window.localStorage.getItem("accessToken"));
const dispatch = useDispatch();
useEffect(() => {
if (token && token.sub) {
console.log("유효한 토큰:", token);
dispatch(callGetMemberAPI({ memberId: token.sub }));
} else {
console.error("유효하지 않은 토큰 또는 sub 값 없음!");
}
}, [token]);
// 선택한 검색 카테고리 관리
const [selectCategory, setSelectCategory] = useState([])
const [selectCompany, setSelectCompany] = useState([])
return (
<Routes>
<Route path='/' element={<UserLayout selectCategory={selectCategory} setSelectCategory={setSelectCategory}
selectCompany={selectCompany} setSelectCompany={setSelectCompany} />} >
<Route index element={<Main />} />
<Route path='/mypage' element={<MyPage />}>
<Route index element={<Orders />} />
</Route>
<Route path='list' element={<ListPage selectCategory={selectCategory} selectCompany={selectCompany} />} />
<Route path='test' element={<Test />} />
<Route path='inquiry' element={<Inquiry />} />
<Route path='/owner' element={<OwnerLayout />}>
<Route index element={<OwnerMyPage />} />
<Route path='product' element={<OwnerProducts />} />
<Route path='register' element={<OwnerRegister />} />
</Route>
</Route>
<Route path='/login' element={<Login />} />
<Route path='/signup' element={<Signup />} />
<Route path='/admin' element={<AdminLayout />}>
<Route index element={<AdminMain />} />
<Route path='rentals' element={<Rental />} />
<Route path='authority' element={<AuthorityLayout />}>
<Route path='user' element={<AdminUser />} />
</Route>
<Route path='product' element={<AdminProduct />} />
</Route>
</Routes>
);
}
export default App;
useEffect 훅으로 특정 상태(token)가 변경될 때마다 실행되게 하였다.
이제 새로 고침을 하든, 다른 페이지를 가든 토큰 정보가 남아있어서 활용하기 쉬워졌다.