리액트 프로젝트와 소소한 트러블들 (1)

WOODIE·2025년 3월 4일
0

#Record

목록 보기
22/24
post-thumbnail

1.

vite 환경에서 배포 시 로컬 이미지 / 비디오 소스 출력하는 방법

📌 assets 폴더에 이미지를 넣어 두었는데 출력되지 않는다?
vite에서 영상 같은 정적 파일은 public에 넣어 보관하는 것을 권장하고 있다. 왜냐하면 public 에 넣은 파일은 {배포주소}/public/image/파일이름 으로 인식하는 것이 아니라 {배포주소}/image/파일이름 으로 인식하기 때문이라고 한다.

image 뿐 아니라 video 와 같은 정적 데이터들은 웬만하면 public 폴더로!


2.

📌 문제 발생 : 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 요소를 적용하거나 제거한다.


3.

📌 useLocation( )

현재 URL 의 정보를 가져오는 훅이다. 이를 사용하면 얻을 수 있는 객체는 다음과 같다.

{
  "pathname": "/login",
  "search": "?query=test",
  "hash": "",
  "state": null,
  "key": "abc123"
}

👀 useLocation을 언제 사용할까?

현재 URL에 따라 UI를 변경할 때
✅ 현재 경로(pathname)를 조건으로 특정 스타일 적용할 때
쿼리 스트링(search)을 파싱하여 데이터 활용할 때
✅ 페이지 이동 시(useNavigate) 전달한 state 값을 가져올 때

=> UI 변경, 인증 페이지 처리, URL 기반 데이터 활용 등에 유용하게 사용된다!


4.

replace 속성

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;

5.

로그인하지 않은 사용자가 Protect 된 페이지, 즉 MyPage 나 Post 관련 페이지에 접근을 시도할 경우, 로그인 페이지로 자동으로 이동하게 되는 로직을 구현했다.

그런데 페이지만 냅다 이동해 버리고, 아무런 안내가 뜨지 않으니 사용자 경험이 영 좋지 못한 로직이 되었다. 그래서 페이지 이동 전에 sweetAlert2 를 사용한 사용자 안내 팝업을 띄워준 후, 로그인 페이지로 이동하도록 유도하는 로직을 짰다.

그런데

React 공식 문서에서 useNavigate()를 useEffect에서 사용할 때 의존성 배열에 포함할 것을 권장!!


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;

의존성 배열 안에 navigate 를 넣는 이유?

React 에서는 useNavigate()다른 라우터 변경과 함께 변경될 수 있는 함수로 간주된다. 따라서, navigate 가 변경될 경우 useEffect() 가 다시 실행되어 최신 상태를 반영할 수 있도록 설정.

만약 navigate 가 변경되었는데 useEffect 가 실행되지 않는다면, 이전 navigate 를 참조하여 네비게이션이 정상적으로 동작하지 않을 수 있음.

useNavigate() 내부 구현이 변경되거나, 새로운 라우팅 설정이 적용되었을 때 최신 navigate 를 반영하지 못하는 문제가 발생할 가능성이 있음.

✅ 결론

✔ 최신 navigate를 사용하도록 보장하여 네비게이션 관련 버그를 예방할 수 있다.

0개의 댓글