리액트 공부하기 - React Router 리액트 라우터 심화공부

모야.. 실무에서 쓰려니까 뭐 더 많이 알아야 하잖아?
프로젝트에서 페이지는 아주 많아질테니.. 라우터 추가 공부 필요하겠잖아 ?
라우터의 기초 내용은 아래 링크에서 볼 수 있다.
리액트 공부하기 - React Router 리액트 라우터
1. 리액트 라우터란?2. 리액트 라우터 사용하는 법3. 궁금증 두가지. (왜 설치를 따로해야하는가? 주소를 이동하는건데 새로고침이 안된다고 ?!)4. 리액트 라우터 주요 컴포넌트5. 리액트 라우터 주
creamymood.tistory.com
1. useNavigate() 이런 훅을 쓸 때, 바로 쓰진 못하고 변수에 할당에서 쓰더라.
이유는 ? ↓
useNavigate() 같은 훅을 바로 호출해서 못 쓰고 변수에 할당해서 쓰는 이유는?
const navigate = useNavigate();
navigate('/home');
- React 훅은 함수 컴포넌트 또는 커스텀 훅 안에서만 호출 가능해.
- 훅은 호출되는 위치(컴포넌트 렌더링 과정)에서 내부 상태나 컨텍스트를 관리하기 위해 만들어졌기 때문이야.
- 그래서 훅을 호출할 때는 결과(함수, 상태값 등)를 변수에 받아서 사용해야 해.
- useNavigate()는 함수를 반환하는 훅이기 때문에, 반환된 함수를 변수에 저장한 후 호출해서 경로를 이동해.
- 훅이 반환하는 함수를 직접 호출하는 건 가능하지만, useNavigate()를 호출하고 바로 뒤에 경로를 넣어서 쓰는 문법(예: useNavigate()('/home'))는 일반적이지 않고 가독성도 떨어짐.
모든 훅이 다 그런가?
- 네, React 내장 훅(useState, useEffect, useContext 등)과 커스텀 훅 모두 호출 결과를 변수에 할당하거나 바로 사용해야 함.
- 훅은 반드시 React 함수 컴포넌트의 최상위 또는 다른 훅 안에서 호출돼야 한다는 규칙도 있어(조건문이나 반복문 안에서 호출하면 안 됨).
이유는 아래 블로그에서 조금 더 자세히 다뤄보았다.
리액트 공부하기 - hooks를 최상단에 작성 해야 하는 이유? 변수에 담아서 사용하는 이유?
훅이란?아래 블로그에서 자세히 읽어볼 수 있다. 리액트 공부하기 - custom hooks? 그냥 함수 차이?custom hooks를 공부하며 헷갈리게 된 또 기본 개념- 다시 짚고 갑시다.우선 훅(hook)이 뭘까. 리액트(Reac
creamymood.tistory.com
2. 페이지를 보호할 땐, 껍데기wrapper를 하나 만들어서 씌울 수 있다. 🍑
3. 라우터에서 element 부분
리액트 라우터(React Router)에서 element는 특정 경로(URL)에 도달했을 때 화면에 렌더링할 컴포넌트를 지정하는 부분입니다.
기본 문법 예시
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}
element의 역할
- element={<Home />}는 / 경로일 때 <Home /> 컴포넌트를 렌더링하라는 의미입니다.
- 즉, element에는 JSX 형태로 렌더링하고 싶은 컴포넌트 인스턴스를 넣는다고 생각하면 돼요.
추가 설명
path | URL 경로를 지정합니다. |
element | 해당 경로에 도달했을 때 보여줄 컴포넌트를 JSX 형태로 지정합니다. |
예를 들어 /about으로 이동하면 <About /> 컴포넌트가 보이는 거죠.
자주 하는 실수
❌ element={About} 이렇게 쓰면 오류가 납니다.
✅ 반드시 JSX 형태로: element={<About />}
4. <Navigate to="..." replace />에서 replace란?
<Navigate to="/mypage" replace />에서 replace는 고정 문법이라기보다 상황에 따라 쓰는 옵션이야.
1. <Navigate to="..." replace />에서 replace란?
- 기본적으로 Navigate를 사용하면 현재 페이지를 스택에 쌓고 새 페이지로 이동해.
- replace를 쓰면 브라우저 히스토리에서 현재 페이지를 새 페이지로 대체해.
- 즉, 사용자가 뒤로가기 했을 때 리다이렉트된 페이지로 다시 돌아오는 걸 방지해줘.
- 로그인 리다이렉트처럼 이전 페이지로 돌아가면 안 되는 경우에 주로 사용해.
<Navigate to="/mypage" replace />
- replace 없으면 뒤로가기 시 로그인 페이지로 돌아감
- replace 있으면 로그인 페이지 히스토리 기록이 없어 뒤로가기 시 이전 페이지로 이동
replace를 쓰면, 브라우저 '뒤로 가기'를 눌렀을 때 리디렉션 이전 페이지로 돌아가지 않아!
🔍 어떻게 동작하냐면
<Navigate to="/mypage" replace />
이렇게 하면:
- 현재 URL을 /mypage로 바꾸되, 브라우저 히스토리에 /login을 남기지 않아.
- 그래서 사용자가 브라우저에서 뒤로가기를 눌러도 /login으로 다시 못 돌아감.
👀 예를 들어서
replace ❌ 없는 경우:
- 사용자가 /login 들어감
- 로그인 성공 → Navigate to="/mypage" (기본은 replace: false)
- 브라우저 히스토리: /login → /mypage
- 사용자가 뒤로가기 누르면... 👉 다시 /login으로 감! (근데 이미 로그인된 상태니까 이상함)
replace ✅ 있는 경우:
- 사용자가 /login 들어감
- 로그인 성공 → Navigate to="/mypage" replace
- 브라우저 히스토리: /mypage만 남음
- 뒤로가기 눌러도 👉 /login은 히스토리에 없으니까 못 감
📌 요약
- replace는 히스토리 스택을 덮어씀
- 뒤로가기 눌렀을 때 이전 페이지로 안 돌아가게 함
- 보통 로그인/로그아웃/자동 리디렉션 시 사용
**히스토리는 없어서, 뒤로가기로는 접근이 안되지만..
wrapper로 보호 컴포넌트로 감싸줘야 url에 쳐서 접근하는 것도 막을 수 있음.
5. 실무에서 자주 쓰이는 router hook
실무에서 자주 쓰이는 React Router 훅 정리
이름 | 용도 | 예시 및 설명 |
useNavigate | 프로그래밍 방식으로 페이지 이동을 할 때 사용 | const navigate = useNavigate(); navigate('/home'); |
useParams | URL 파라미터 값을 가져올 때 사용 | /user/:id 경로에서 const { id } = useParams(); |
useLocation | 현재 URL, 쿼리스트링, 상태 등 위치 정보를 얻을 때 사용 | const location = useLocation(); console.log(location.pathname); |
useMatch | 현재 경로가 특정 경로와 일치하는지 확인할 때 사용 | const match = useMatch('/profile/:id'); |
<Outlet> | 중첩 라우팅에서 자식 컴포넌트를 렌더링할 때 사용 | 상위 라우트 컴포넌트에 배치해 하위 라우트 렌더링 |
<Navigate> | 리다이렉션(강제 경로 이동) 시 사용 | <Navigate to="/login" replace /> |
6. useNavigate의 다양한 옵션
<Navigate>의 replace 외에 주요 속성들
<Navigate>는 리다이렉트를 위한 컴포넌트라서 크게 복잡하지 않지만, 몇 가지 중요한 속성 있어.
속성명 | 설명 | 기본값 / 예시 |
to | 이동할 경로 지정 (필수) | /mypage, { pathname: '/home' } 등 |
replace | 현재 히스토리 기록을 대체할지 여부 | false (기본값), true로 설정하면 replace 동작 |
state | 이동 시 전달할 상태 데이터 | { from: '/login' } 등 |
relative | 상대 경로로 해석할지 여부 (React Router v6.12부터) | false 기본값 |
조금 더 자세히
<Navigate
to="/mypage"
replace={true}
state={{ from: '/login' }}
/>
- to: 이동할 경로. 문자열이나 객체로 쓸 수 있어.
- replace: true면 히스토리에서 현재 페이지를 새 페이지로 대체. 뒤로가기 시 이전 페이지로 돌아가지 않음.
- state: 이동할 때 추가 데이터를 넘길 수 있어. 나중에 useLocation() 훅에서 location.state로 받을 수 있어.
- relative: 경로를 상대 경로로 해석할지 설정. 잘 쓰이지는 않음.
참고로 useNavigate 함수도 비슷하게 옵션을 줄 수 있어요
navigate('/mypage', { replace: true, state: { from: '/login' } });
- navigate 함수는 두 번째 인자로 옵션 객체를 받음
- 여기서도 replace와 state를 설정 가능!
7. 너무 추상적이어서 볼 때 마다 헷갈리던 outlet . 아래 내용 읽고 조금은 해결
네브바는 항상 화면에 보여야 해
- 네브바 안에 "로그인 / 검색 / 로고" 버튼이 있어
- 이 버튼들을 클릭하면 각각 로그인 페이지 / 검색 페이지 / 로고 페이지로 이동해야 해
- 근데 그때도 네브바는 계속 보여야 해
🧸 그림으로 표현하면 이런 구조!
전체 App
├─ NavBar (항상 보여야 해!)
│ ├─ [로그인] [검색] [로고] ← 버튼들
│ └─ Outlet 자리 → 여기에 로그인/검색/로고 페이지가 하나씩 바뀌며 들어옴
🔨 구현 흐름 예시
1. NavBar.js
import { Link, Outlet } from "react-router-dom";
function NavBar() {
return (
<div>
<nav style={{ background: '#eee', padding: '10px' }}>
<Link to="/login">로그인</Link> |
<Link to="/search">검색</Link> |
<Link to="/logo">로고</Link>
</nav>
{/* 이 자리에 해당 페이지가 바뀌며 들어옴 */}
<Outlet />
</div>
);
}
export default NavBar;
<nav>로 감싸진건 항상 보여야 하는 고정된 레이아웃
그 밑에 outlet으로 된 건, 밑에 app.jsx에서 라우터로 감싸진
NavBar 자식 요소들이 모두 렌더링 될 수 있는 자리!
2. App.js
import { BrowserRouter, Routes, Route } from "react-router-dom";
import NavBar from "./NavBar";
import Login from "./pages/Login";
import Search from "./pages/Search";
import Logo from "./pages/Logo";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<NavBar />}>
<Route path="login" element={<Login />} />
<Route path="search" element={<Search />} />
<Route path="logo" element={<Logo />} />
</Route>
</Routes>
</BrowserRouter>
);
}
<NavBar /> | 항상 보여야 하는 레이아웃 (고정) |
<Outlet /> | 현재 URL에 따라 Login, Search, Logo 페이지 중 하나가 여기에 들어옴 |
<Route path="/" element={<NavBar />} > ... </Route> | 이 구조 덕분에 NavBar는 계속 보이고, 그 아래 내용만 바뀜 |
지난 영화 페이지 프로젝트를 기준으로
🧁 쉽게 비유하면
🍰 케이크(전체 화면) = Layout
- 항상 보이는 틀: 네브바, 푸터 등 (고정된 것)
- 안에 바뀌는 크림: 각 페이지의 내용 (Outlet으로 들어감)
8. 동적 파라미터 설정하기
동적 파라미터란?
예를 들어, 우리 웹사이트에 여러 도시의 정보를 보여주는 페이지가 있다고 생각해본다면,
/detail/seoul
/detail/tokyo
/detail/newyork
이렇게 도시 이름만 바뀌는 페이지가 있으면, 각각 따로 라우트를 만들지 않고 하나의 라우터로 처리할 수 있다.
그걸 가능하게 해주는 게 바로 동적 파라미터
어떻게 쓰는지?
1. Route에서 정의:
<Route path="/detail/:city" element={<Detail />} />
여기서 :city는 변하는 값이 들어올 자리다.
예를 들어 /detail/seoul로 들어오면, city는 "seoul"이 되는 것.
2. navigate 할 때
navigate(`/detail/${searchInputValue}`)
만약 searchInputValue가 "tokyo"라면,
이건 결국 이렇게 되는 것:
navigate("/detail/tokyo")
3. Detail 컴포넌트에서 그 값 꺼내기:
import { useParams } from 'react-router-dom';
const Detail = () => {
const { city } = useParams(); // city는 URL의 값
return <div>{city}의 정보입니다.</div>;
}
궁금한 것!
// 라우터 설정
<Route path='/detail/:city' element={<Detail />} />
라우터에서의 동적파라미터에서 : 뒤에는 아무거나 들어가는 건가?
=>
:뒤에 오는 단어는 마음대로 정할 수 있는 이름
단, 그 값은 URL의 일부로부터 받아오는 변수명이기 때문에 의미 있게 지으면 좋다.
예시 1: 도시 이름일 때
<Route path="/detail/:city" element={<Detail />} />
- 여기서 :city는 URL에서 받아오는 값이야.
- 실제 URL이 /detail/seoul이면, city = "seoul"이 됨.
예시 2: 유저 ID일 때
<Route path="/user/:userId" element={<UserProfile />} />
- 이 경우 URL이 /user/123이면, userId = "123"이 됨.
규칙 정리
- : 뒤에는 원하는 이름을 붙여도 됨 (:id, :name, :productSlug 등등).
- 단, useParams()로 꺼낼 때도 그 이름을 그대로 써야 해.
예:
<Route path="/post/:postId" element={<Post />} />
// Post.jsx
const { postId } = useParams(); // postId로 꺼내야 함!
이렇게 하면 안 됌:
<Route path="/post/:id" element={<Post />} />
// 그런데 이렇게 꺼냄
const { postId } = useParams(); // ❌ undefined가 나와
왜냐하면 :id라고 했으니까, id로 꺼내야 맞음.