[React] useNavigate 훅을 사용한 페이지 이동/ Blocking 훅을 이용한 페이지 이탈 방지/ useBlocker 훅과createBrowserRouter

겨레·2024년 12월 4일

[React] 리액트 스터디

목록 보기
75/95

프론트는 확실히 빠르게 변하는 것 같다...
개정판임에도 불구하고 책을 보면서 랜더링이 안 될 때가 꽤 많았는데,
구글링 또는 쳇지피티로 확인해보면 기능이 사라지거나 다른 게 생겨서 안되는 거였다;;

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;
    

  • App.jsx
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 이상에서 createBrowserRouterRouterProvider를 사용하여 라우팅을 설정하는 방식이 필요하다는 의미이다.

    • 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를 사용하는 방식으로 전환해야 한다.


  • React Router v6.4 이상에서 제공되는 useBlocker와 createBrowserRouter를 사용해 페이지 이탈 방지 기능을 구현한 예제
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

  • 사용자가 페이지를 떠나려고 할 때, 이탈을 방지하는 기능을 제공.
  • 사용자가 페이지를 떠나려고 할 때 window.confirm을 사용해 "정말 떠나시겠습니까?"라는 확인 메시지를 띄우고, 사용자가 "확인"을 클릭할 때만 페이지 이동을 허용함.

✔ createBrowserRouter

  • React Router v6.4에서 추가된 새로운 라우터 설정 방식으로 라우터 설정을 객체 형식으로 정의할 수 있음.
  • 위 예제에서는 /useNavigate 경로에 UseNavigate_sample 컴포넌트를 렌더링하고, / 경로에는 홈 페이지를 렌더링함.

✔ useNavigate

  • useNavigate는 페이지 이동을 위한 훅.
  • 위 예제에서는 navigate(-1)을 사용하여 뒤로 가기, navigate("/")를 사용하여 홈으로 가기 기능을 구현함.

✔ setIsBlocking

  • setIsBlocking은 페이지 이탈을 차단할지 여부를 결정하는 상태 변수로 "차단 해제"와 "차단 활성화" 버튼을 눌러 페이지 이탈 방지를 켜거나 끌 수 있음.

핵심 흐름

  • isBlocking 상태가 true일 때, 페이지를 떠나려고 할 때 확인 창을 띄워서 이동을 차단함.
  • setIsBlocking(!isBlocking)을 통해 버튼을 눌러 isBlocking 상태를 바꿀 수 있음.
    • "차단 활성화" 버튼 클릭 ⇒ 페이지 이동 차단
    • "차단 해제" 버튼 클릭 ⇒ 페이지 이동 허용
  • createBrowserRouter를 사용해 페이지 경로를 설정하고, 해당 경로에서 컴포넌트를 렌더링함.








(+) TMI
비슷해 보이는데 너무 헷갈린다....
백도 어렵지만 프론트는 빠른 변화로 인한 또다른 어려움이 있다는 걸
다시 한 번 느끼는 순간이었다ㅠㅠ

profile
호떡 신문지에서 개발자로 환생

0개의 댓글