📌 assets
폴더에 이미지를 넣어 두었는데 출력되지 않는다?
vite에서 영상 같은 정적 파일은 public에 넣어 보관하는 것을 권장하고 있다. 왜냐하면 public
에 넣은 파일은 {배포주소}/public/image/파일이름
으로 인식하는 것이 아니라 {배포주소}/image/파일이름
으로 인식하기 때문이라고 한다.
image
뿐 아니라 video
와 같은 정적 데이터들은 웬만하면 public
폴더로!
📌 문제 발생 : Router 파일에서 Header를 적용할 때에, 헤더의 높이만큼 pt-20을 전역으로 줌
<BrowserRouter>
{/* Header 컴포넌트 전역 적용 */}
<Header />
{/* Header 높이만큼 여백 주기 */}
<div className="pt-20">
<Routes>
<Route path={PATH.HOME} element={<DateRoutePage />} />
<Route path={PATH.LOGIN} element={<LoginPage />} />
<Route path={PATH.SIGNUP} element={<SignupPage />} />
<Route path={PATH.MYPAGE} element={<MyPage />} />
<Route path={PATH.DATEDETAIL} element={<DateRouteDetail />} />
<Route path={PATH.WRITEPOST} element={<WritePostPage />} />
<Route path={PATH.NAVITALK} element={<NaviTalkPage />} />
<Route path={PATH.NAVITALKDETAIL} element={<NaviTalkDetail />} />
<Route path={PATH.DATEWRITE} element={<DateRouteWritePage />} />
<Route path={PATH.PROFILE} element={<ProfilePage />} />
</Routes>
</div>
</BrowserRouter>
이렇게 하면 h-screen(100vh)
와 함께 적용될 시에 전체 높이를 초과하게 되어 불필요한 스크롤이 생기게 된다. 이를 방지하기 위해 calc
함수로 헤더 높이만큼 빼주는 방법, pt
이 아니라 mt
을 적용하는 방법 등 여러 가지 방법이 있다.
하지만 이번 프로젝트의 경우, 혹시나 내가 작업하지 않는 페이지에서도 동일한 문제가 발생할 경우를 대비하여 useLocation
을 사용하여 특정 페이지에서만 pt-20
요소를 제거하는 로직을 적용했다.
const location = useLocation();
useLocation
을 사용하여 현재 경로를 가져온다.
const fullScreenPages = [PATH.LOGIN, PATH.SIGNUP];
100vh
를 적용할 페이지를 배열로 지정해준다.
<div className={`${noPaddingPages.includes(location.pathname) ? "" : "pt-20"}`}>
현재 경로가 해당 배열에 포함되는지 확인한 후 pt-20
요소를 적용하거나 제거한다.
📌 useLocation( )
현재 URL 의 정보를 가져오는 훅이다. 이를 사용하면 얻을 수 있는 객체는 다음과 같다.
{
"pathname": "/login",
"search": "?query=test",
"hash": "",
"state": null,
"key": "abc123"
}
✅ 현재 URL에 따라 UI를 변경할 때
✅ 현재 경로(pathname)를 조건으로 특정 스타일 적용할 때
✅ 쿼리 스트링(search)을 파싱하여 데이터 활용할 때
✅ 페이지 이동 시(useNavigate) 전달한 state 값을 가져올 때
=> UI 변경, 인증 페이지 처리, URL 기반 데이터 활용 등에 유용하게 사용된다!
replace
속성은 현재 페이지를 새로운 페이지로 대체하는 역할을 한다. 즉, 현재 페이지를 로그에 저장하지 않고 이동한다.
이 속성을 사용하면, 사용자가 로그인을 하고 뒤로 가기를 눌렀을 때, 로그인 페이지로 다시 돌아가지 않도록 방지할 수 있다!
import { Navigate } from "react-router-dom";
const ProtectRoute = ({ children }) => {
const session = JSON.parse(localStorage.getItem("session"));
return session ? children : <Navigate to="/login" replace />; // 뒤로 가기 방지
};
export default ProtectRoute;
로그인하지 않은 사용자가 Protect 된 페이지, 즉 MyPage 나 Post 관련 페이지에 접근을 시도할 경우, 로그인 페이지로 자동으로 이동하게 되는 로직을 구현했다.
그런데 페이지만 냅다 이동해 버리고, 아무런 안내가 뜨지 않으니 사용자 경험이 영 좋지 못한 로직이 되었다. 그래서 페이지 이동 전에 sweetAlert2
를 사용한 사용자 안내 팝업을 띄워준 후, 로그인 페이지로 이동하도록 유도하는 로직을 짰다.
그런데
import { useNavigate } from 'react-router-dom';
import { PATH } from '../shared/PATH';
import { useEffect } from 'react';
import { AlertInfo } from '../common/Alert';
const ProtectRoute = ({ children }) => {
const navigate = useNavigate();
useEffect(() => {
const session = JSON.parse(localStorage.getItem('session'));
if (!session) {
AlertInfo('잠깐!', '로그인이 필요한 페이지입니다.');
navigate(PATH.LOGIN);
}
}, [navigate]); // 이렇게 의존성 배열 안에 navigate를 넣어 주어야 한다!
return children;
};
export default ProtectRoute;
✔ React
에서는 useNavigate()
가 다른 라우터 변경과 함께 변경될 수 있는 함수로 간주된다. 따라서, navigate
가 변경될 경우 useEffect()
가 다시 실행되어 최신 상태를 반영할 수 있도록 설정.
만약 navigate
가 변경되었는데 useEffect
가 실행되지 않는다면, 이전 navigate
를 참조하여 네비게이션이 정상적으로 동작하지 않을 수 있음.
useNavigate()
내부 구현이 변경되거나, 새로운 라우팅 설정이 적용되었을 때 최신 navigate
를 반영하지 못하는 문제가 발생할 가능성이 있음.
✔ 최신 navigate를 사용하도록 보장하여 네비게이션 관련 버그를 예방할 수 있다.