프론트는 확실히 빠르게 변하는 것 같다...
개정판임에도 불구하고 책을 보면서 랜더링이 안 될 때가 꽤 많았는데,
구글링 또는 쳇지피티로 확인해보면 기능이 사라지거나 다른 게 생겨서 안되는 거였다;;
13장만 하더라도 바뀐게 2~3개인가 발견했다.
지금 이야기 할 부분 역시 바껴써 추가적으로 작성하는 내용이다.
책에는 리액트 라우터 부가 기능으로 history가 나왔는데,
구글링해 보니까 글이 죄다 21~22년에서 멈춰있다.
확인해 보니 history가 useNavigate 훅으로 사용하는 걸로 바뀌었다고 한다.
📍 useNavigate 훅
useNavigate는 함수형 컴포넌트 내에서 페이지 이동하는 데에 사용된다. 해당 훅은 navigate( ) 함수를 반환하는데, 이 함수는 경로를 인수로 받아 해당 경로로 이동한다.
import { useNavigate } from 'react-router-dom';
function MyComponent() {
const navigate = useNavigate();
const goToHome = () => {
navigate('/'); // '/home' 경로로 이동
};
const goToAbout = () => {
navigate('/about'); // '/about' 경로로 이동
};
return (
<div>
<button onClick={goToHome}>Go to Home</button>
<button onClick={goToAbout}>Go to About</button>
</div>
);
}
useNavigate 사용 시 옵션
아래와 같은 옵션 사항들이 있음.... 더 있을 듯!
상태 추가 : navigate('/path', { state: { someData: 'value' } })
경로로 이동할 때 상태를 추가해 페이지 간에 데이터를 전달할 수 있음.
뒤로 가기 : navigate(-1)
이전 페이지로 돌아갈 수 있음.
앞으로 가기 : navigate(1)
새 페이지로 이동 : navigate('/path', { replace: true })
현재 페이지를 새 페이지로 교체함.
📍 Blocking 훅
Blocking을 통해 사용자가 페이지를 떠나려고 할 때 경고 메시지를 표시하거나 네비게이션을 막을 수 있는 기능이다.
- React Router v6에서 페이지를 떠날 때 확인 메시지를 표시하는 기능은 Prompt 컴포넌트를 사용하여 구현할 수 있습니다.
이제 동작을 실제로 확인해 보자!
UseNavigate_sample.jsx
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
const UseNavigate_sample = () => {
const navigate = useNavigate();
const [isBlocking, setIsBlocking] = useState(true); // 페이지 떠날 때 차단 여부
// 뒤로 가기
const handleGoBack = () => {
if (isBlocking && !window.confirm("정말 떠나실 건가요?")) {
return; // 사용자가 취소하면 이동하지 않음
}
navigate(-1);
};
// 홈으로 이동
const handleGoHome = () => {
if (isBlocking && !window.confirm("정말 떠나실 건가요?")) {
return; // 사용자가 취소하면 이동하지 않음
}
navigate("/");
};
// 페이지 떠날 때 이탈 방지
useEffect(() => {
const handleBeforeUnload = (event) => {
if (isBlocking) {
// 페이지를 떠나려고 할 때 confirm 창을 띄웁니다.
const confirmation = window.confirm("정말 떠나실 건가요?");
if (!confirmation) {
event.preventDefault(); // 취소하면 페이지 이동을 막음
}
}
};
// 페이지를 떠날 때 알림을 표시하기 위한 이벤트 리스너 추가
window.addEventListener("beforeunload", handleBeforeUnload);
return () => {
window.removeEventListener("beforeunload", handleBeforeUnload);
};
}, [isBlocking]);
return (
<div>
<button onClick={handleGoBack}>뒤로</button>
<button onClick={handleGoHome}>홈으로</button>
</div>
);
};
export default UseNavigate_sample;
import React from "react";
import { Routes, Route, Link } from "react-router-dom"; // Link 사용 임포트
import "./App.css";
import About from "./About";
import Info from "./Info";
import Home from "./Home";
import Profiles from "./Profiles";
import UseNavigate_sample from "./UseNavigate_sample";
const App = () => {
return (
<div>
<ul>
<li>
<Link to="/">홈</Link>
</li>
<li>
<Link to="/about">소개</Link>
</li>
<li>
<Link to="/profiles">프로필</Link>
</li>
<li>
<Link to="/useNavigate">UseNavigate_sample 예제</Link>
</li>
</ul>
<hr />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/info" element={<Info />} />
<Route path="/profiles/*" element={<Profiles />} />
<Route path="/useNavigate" element={<UseNavigate_sample />} />
</Routes>
</div>
);
};
export default App;
UseNavigate_sample 예제를 클릭하고 들어가면 '뒤로 가기', '홈으로 가기' 버튼이 나온다.

각각 버튼을 한 번 눌러보자!

그러면 정말 해당 페이지를 떠날건지 물어보는 창이 나온다.
확인을 누르면 이전 페이지로, 홈으로 이동되고
취소를 누르면 UseNavigate_sample 페이지 그대로 유지된다.
📍 useBlocker 훅
React Router v6에서 제공하는 새로운 훅으로 사용자가 페이지 이동을 시도할 때 이를 차단하고, 확인 대화 상자를 띄워서 이동 여부를 사용자에게 묻게 하는 기능을 제공한다.
- React Router에서 네비게이션을 제어하고, 사용자가 페이지를 떠나기 전에 특정 조건을 확인하거나 경고 메시지를 표시하는 데 사용된다.
- useBlocker는 Prompt와 비슷한 역할을 하지만 더 강력한 제어를 제공한다.
- useBlocker는 useNavigate와 함께 사용된다.
❓🤔 createBrowserRouter로 라우터를 만들어야 쓸 수 있다는 건 무슨 말일까?
react-router-dom의 v6.4 이상에서 createBrowserRouter와 RouterProvider를 사용하여 라우팅을 설정하는 방식이 필요하다는 의미이다.
createBrowserRouter를 사용해 라우터를 설정한 예시
import React from "react";
import ReactDOM from "react-dom";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import UseNavigate_sample from "./UseNavigate_sample";
import Home from "./Home";
import About from "./About";
// 라우터 설정
const router = createBrowserRouter([
{
path: "/",
element: <Home />,
},
{
path: "/about",
element: <About />,
},
{
path: "/useNavigate",
element: <UseNavigate_sample />,
},
]);
const App = () => {
return (
<RouterProvider router={router} />
);
};
ReactDOM.render(<App />, document.getElementById("root"));
✔ createBrowserRouter
라우팅 정보를 배열로 받아 라우터 객체를 생성한다. 각 라우트에는 path와 element가 포함되어 있다.
✔ RouterProvider
createBrowserRouter로 생성된 라우터 객체를 이 컴포넌트에 전달하여 라우팅을 설정한다.
✔ UseNavigate_sample
useBlocker 훅을 사용하는 컴포넌트를 이 라우터 내에서 사용할 수 있다.
❓🤔 그렇다면 왜 createBrowserRouter를 사용해야 하나?
React Router v6.4 이상에서는 useBlocker 훅을 사용하는 방식이 createBrowserRouter로 설정된 라우터에서만 제대로 작동하기 때문!!!
만약 BrowserRouter를 사용하고 있다면, useBlocker는 동작하지 않거나 예상대로 작동하지 않을 수 있다. 따라서, useBlocker를 포함한 라우팅 기능을 제대로 사용하려면 createBrowserRouter와 RouterProvider를 사용하는 방식으로 전환해야 한다.
import React, { useState } from "react";
import { createBrowserRouter, RouterProvider, useNavigate, useBlocker } from "react-router-dom";
const UseNavigate_sample = () => {
const navigate = useNavigate();
const [isBlocking, setIsBlocking] = useState(true); // 페이지 떠날 때 차단 여부
// 페이지 이동을 차단하고, 확인 메시지를 표시
useBlocker((tx) => {
if (isBlocking && !window.confirm("정말 떠나실 건가요?")) {
tx.retry(); // 사용자가 '확인'을 클릭하면 페이지 이동을 허용
} else {
tx.retry(); // 사용자가 '취소'를 클릭하면 이동하지 않음
}
}, isBlocking);
const handleGoBack = () => {
navigate(-1); // 페이지를 뒤로 이동
};
const handleGoHome = () => {
navigate("/"); // 홈 페이지로 이동
};
return (
<div>
<button onClick={handleGoBack}>뒤로</button>
<button onClick={handleGoHome}>홈으로</button>
<button onClick={() => setIsBlocking(!isBlocking)}>
{isBlocking ? "차단 해제" : "차단 활성화"}
</button>
</div>
);
};
// 라우터 설정
const router = createBrowserRouter([
{
path: "/useNavigate",
element: <UseNavigate_sample />,
},
{
path: "/",
element: <div>홈 페이지</div>,
},
]);
const App = () => {
return <RouterProvider router={router} />;
};
export default App;
✔ useBlocker
✔ createBrowserRouter
✔ useNavigate
✔ setIsBlocking
✅ 핵심 흐름
(+) TMI
비슷해 보이는데 너무 헷갈린다....
백도 어렵지만 프론트는 빠른 변화로 인한 또다른 어려움이 있다는 걸
다시 한 번 느끼는 순간이었다ㅠㅠ