조각조각 - CRA 라우팅(중첩 라우터와 자손 라우터, useRoutes, useNavigate)

eocode·2023년 3월 23일
0

리액트 조각조각

목록 보기
8/11
post-thumbnail

🔗 조각조각 - CRA 라우팅(react-router-dom v6, Router, Routes, Switch)
앞 게시물에 이어서 react-router-dom v6.0의 중첩 라우터, 자손 라우터, useRoutes, useNavigate에 대해 살펴보겠습니다.

중첩 라우터, 자손 라우터

이전 react-router-dom v5.0, v6.0의 차이와 기본적인 사용법을 알아보았습니다. 하나의 url에 하나의 페이지만 렌더링 되도록하기 위해 react-router-dom v5.0에서의 Switch, react-router-dom v6.0에서의 Routes가 사용됨을 파악하였습니다.

www.fe.com/a로 접근시 특정 페이지 하나 렌더링
www.fe.com/b로 접근시 특정 페이지 하나 렌더링
www.fe.com/b/sub로 접근시 특정 페이지 하나 렌더링
...

이 방식은 url 하나에 하나의 페이지 컴포넌트를 연결시켜 요청이 있을때 하나의 페이지 컴포넌트를 렌더링해주는 것입니다.

그렇다면 특정 팝업(추가 컴포넌트)에 url 지정이 가능할까?

글쓰기 버튼을 눌렀을때 글쓰기 컴포넌트를 팝업 형식으로 뜨도록 구현하는 경우가 있습니다. 이때 글쓰기 팝업을 어떤식으로 구현할까요?

  1. 그냥 컴포넌트 state를 이용한 단순 팝업 컴포넌트 띄우고 닫기로 구현
  2. 팝업이 띄어진 상태를 라우팅 설정하여 구현

1번의 경우 구현이 간단하고 쉽다는 장점이 있지만 단순 state에 따라 팝업 컴포넌트가 열리고 닫히기 때문에 새로고침, 뒤로가기 후 state가 변경되면 복구가 불가능하다는 단점이 존재합니다. 하지만 2번과 같이 라우팅 설정하여 팝업을 띄우는 경우 state의 변화에 따라 팝업을 띄우는것이 아니라 url 접근으로 팝업을 띄우는 것이기 때문에 새로고침이나 뒤로가기시 유지가 가느합니다.

팝업과 같이 특정 컴포넌트를 추가적으로 띄우는 방식으로 중첩 라우터자손 라우터 기능이 있습니다.

중첩 라우터

위에서 예시로든 팝업 글쓰기 창으로 구현 상황을 살펴보겠습니다.

www.test.com/a => a 페이지 렌더링
www.test.com/a/write => a 페이지 위에서 글쓰기 팝업 추가

단순 state로 컴포넌트를 나타나도록 한다면 'www.test.com/a' url로 접근한 a페이지 위에서 모두 처리 됩니다. 반면에 중첩 라우터를 통해 팝업 글쓰기 창을 구현한다면 'www.test.com/a' url로 접근했을때 a 페이지가 렌더링 되고 특정 글쓰기 버튼을 눌렀을때 'www.test.com/a/write' url로 이동되어 글쓰기 팝업이 나타납니다.

구현법

중첩 라우터를 구현하기 위해 < Route>에 < Route>가 포함되도록 코드를 작성합니다.

<Route path="a" element={<A />}>
	<Route path="sub" element={<White />}>
    <Route path="sub2" element={<Sub2 />}>
</Route>

부모 Route path인 a에 접근했을때 A 컴포넌트가 렌더링 됩니다. a/sub 접근 시 A 컴포넌트가 렌더링되고 동시에 White 컴포넌트도 렌더링 됩니다.
이때 반드시 부모 Route가 나타내는 컴포넌트에 자식 컴포넌트가 나타낼 위치를 < Outlet />로 지정해주어야합니다.

구현 코드

// App.tsx

function App() {
  return (
    <Router>
      <Routes>
        <Route path="a" element={<A />}>
          <Route path="sub" element={<White />}>
        </Route>
      </Routes>
    </Router>
  );
}
export default App;

// A.tsx, 글쓰기 팝업이 이 페이지 위에서 나타납니다.

const A = () => {
  return (
    <>
      ... A page ...
      <Outlet /> // 이 위치에 글쓰기 팝업이 나타납니다.
    </>
  );
};
export default A;

🚨 < Outlet />

위 A 컴포넌트 코드 내부에 적혀있드시 중첩되어 나타날 컴포넌트의 위치에 를 꼭 넣어줘야 합니다!!!
만약 의도한대로 컴포넌트가 나타나지 않는다면 기존 컴포넌트에 가려져서 보이지 않은 경우가 있으니 css 설정을 해보시길 바랍니다 :)
< Outlet />를 넣지 않고 왜 안보여야할게 안보일까 오래 고민했습니다 ㅠㅠ

자손 라우터

이어서 글쓰기 팝업을 예시로 살펴보겠습니다. 위 중첩 라우터의 경우 < Route>를 부모-자식관계로 작성하고 부모 컴포넌트에 < Outlet />로 자식 컴포넌트가 나타날 위치를 지정하여 글쓰기 팝업에 url을 지정하여 나타나도록 하였습니다.

자손 라우터의 경우 < Route>를 부모-자식 관계로 작성, < Outlet />로 위치 설정하는 것이 아니라. 직접 자식 컴포넌트에서 < Routes>를 추가, 추가되는 url에 따라 어떤 컴포넌트가 나타나도록 설정하는 방식입니다.

// A.tsx, 자손 라우터로 구현된 경우

const A = () => {
  return (
    <>
      ... A page ...
      <Routes> // 이 위치에 글쓰기 팝업이 나타납니다.
        <Route path="sub" element={<Write />}></Route>
      </Routes>
    </>
  );
};
export default A;

// A.tsx, 중첩 라우터로 구현된 경우

const A = () => {
  return (
    <>
      ... A page ...
      <Outlet />
    </>
  );
};
export default A;

정리

중첩 라우터로 구현한 경우 하나의 컴포넌트에서 라우터를 모두 정리하여 한순에 확인이 가능하다는 장점이 있지만 또 너무 코드가 길어질 수 있다는 단점도 존재합니다. 자손 라우터으로 구현한 경우 한 컴포넌트에서 한번에 모두 확인할 수 없다는 단점이 존재하지만 컴포넌트 마다 코드의 길이가 짧아지고 하나의 원하는 컴포넌트의 자식만 확인 가능하다는 장점이 존재합니다.

중첩 라우터, 자식 라우터 모두 중복해서 사용도 가능합니다. 따라서 각각의 장단점을 확인하고 구현하는 것이 필요합니다.

useRoutes

지금까지 BrowserRouter(Router), Routes, Route를 이용하여 라우트를 정의하는 법을 알아보았습니다. 이 방법 이외에도 useRoutes 훅을 이용해 라우트를 정의하는 방법이 존재합니다. useRoutes 훅을 이용한 방법은 react-router-dom이 v6.0으로 업데이트 되면서 추가된 방식으로 React Router에서 제공하는 훅 중 하나입니다. BrowserRouter(Router), Routes, Route를 통해서 라우트를 구현할 때는 JSX 컴포넌트를 사용하여 정의하지만 useRoutes 훅을 사용한다면 자바스크립트 객체를 사용하여 라우트 구현이 가능합니다.

구현 방식

  1. const router = useRoutes(routes);

  2. path와 element 속성을 가진 객체 배열을 정의합니다.

    const routes = [
        { path: "/", element: <Start /> },
        { path: "main", element: <Main /> }
      ];
  3. 생성한 객체 배열을 useRoutes 훅의 인자로 사용하여 반환값을 얻어내어 컴포넌트 반환값으로 설정합니다.

    const router = useRoutes(routes);
    return router;

    useRoutes의 반환 값은 라우트 트리를 렌더링하는 데 사용되는 React 요소를 뜻합니다.

  4. 🚨 반드시 라우터를 정의하는 컴포넌트를 가 감싸주어야 합니다. Router로 감싸지 않는다면 useRoutes() may be used only in the context of a component에러가 발생합니다.
    🔗 조각조각 - Error: useRoutes() may be used only in the context of a component 에러 처리

    root.render(
      <React.StrictMode>
        <Router>
          <App />
        </Router>
      </React.StrictMode>
    );

구현 코드

BrowserRouter, Routes, Route로 라우트 구현

⌨️ - App.tsx

function App() {
  return (
    <Router>
      <Routes>
        <Route path="a" element={<A />}>
          <Route path="sub" element={<White />}>
        </Route>
      </Routes>
    </Router>
  );
}
export default App;
  

useRoutes로 라우트 구현

App 컴포넌트를 BrowserRouter가 감싸며 path와 element 속성을 가진 객체 배열로 라우트가 구현됩니다.

⌨️ - App.tsx

import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import { useRoutes } from "react-router-dom";

//Pages
import Start from "./pages/Start";
import Main from "./pages/Main";

function App() {
  const routes = [
    { path: "/", element: <Start /> },
    { path: "main", element: <Main /> }
  ];

  const router = useRoutes(routes);
  return router;
}

export default App;

⌨️ - index.tsx

import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter as Router } from "react-router-dom";
import App from "./App";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
    <Router>
      <App />
    </Router>
  </React.StrictMode>
);

useNavigate

SPA에 맞게 필요한 부분만 재렌더링하며 페이지를 이동합니다. React Router에서는 라우터 간 이동하는데 사용됩니다. a 태그와 유사하지만 페이지 전체를 재렌더링하지 않고 라우터 간 이동을 처리합니다.

import { Link } from "react-router-dom";

function Main() {
  return (
    <div>
      <h1>Main</h1>
      <nav>
        <ul>
          <li>
            <Link to="/">Main</Link>
          </li>
          <li>
            <Link to="/sub1">Sub-1</Link>
          </li>
          <li>
            <Link to="/sub2">Sub-2</Link>
          </li>
        </ul>
      </nav>
    </div>
  );
}

a 태그

Link 컴포넌트와 다르게 페이지를 이동하며 페이지 전체가 재렌더링됩니다. 따라서 컴포넌트 state가 유지되지 못합니다. 또 Link 컴포넌트와 다르게 모든 요소를 새로 불러와 속도가 느리다는 단점이 존재합니다.

useNavigate 훅

Link 컴포넌트와 같이 라우터 간 이동하는데 사용되며 모든 페이지가 재렌더링되지 않고 필요한 부분만 재렌더링되며 페이지가 이동됩니다. React Router v5.0에서 라우트 이동시 useHistory가 사용되었지만 v6.0으로 업데이트 되면서 useNavigate가 사용됩니다. useHistory와 마찬가지로 React Router history 객체에 접근하여 push 또는 replace 메서드를 사용하여 다른 라우터로 이동합니다.

useNavigate 훅이 페이지 이동 함수를 반환합니다. 특정 이벤트 발생시 이 함수를 실행시켜 페이지를 이동시킵니다.

import { useNavigate } from "react-router-dom";
  const Start = () => {
	const navigate = useNavigate();
	return(
      <div>	
        <button onClick={() => {navigate("/main");}}>Main</button>                   
      </div>
	)
  }
profile
프론트엔드 개발자

0개의 댓글