그럼에도 불구하고

👨‍💻

[React] react-router-dom v6에 대해 알아보자 본문

React/React basics

[React] react-router-dom v6에 대해 알아보자

zenghyun 2023. 5. 5. 20:02

 

오늘은 react-router-dom v6에 대해 알아보겠습니다.

 

 

react-router-dom v6의 경우 이전 버전과 달라진 점이 있습니다. 

본 게시물은 v6을 기준으로 작성하였습니다. 

 

[ install ]

yarn add react-router-dom

 

 

[ 프로젝트에 라우터 적용 ] 

프로젝트에 리액트 라우터를 적용할 때는 src/index.js 파일에서 react-router-dom에 내장되어 있는 BrowserRouter라는 컴포넌트를 사용하여 감싸면 됩니다. 이 컴포넌트는 웹 애플리케이션에 HTML5 dml History API를 사용하여 페이지를 새로고침하지 않고도 주소를 변경하고, 현재 주소에 관련된 정보를 props로 쉽게 조회하거나 사용할 수 있도록 해 줍니다.

 

📌 index.js 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom'
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
 
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
    <App />
    </BrowserRouter>
  </React.StrictMode>
);
 
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
 
cs

 

 

[ Route 컴포넌트로 특정 주소에 컴포넌트 연결 ]

Route라는 컴포넌트를 사용하여 사용자의 현재 경로에 따라 다른 컴포넌트를 보여줄 수 있습니다. Route 컴포넌트를 사용하면 어떤 규칙을 가진 경로에 어떤 컴포넌트를 보여 줄지 정의할 수 있습니다.

 

사용 방식은 다음과 같습니다.

 

1
2
3
4
5
import { Routes, Route } from "react-router-dom";
 
<Routes>
     <Route path="주소" element={<보여 줄 컴포넌트/>/>
</Routes>
cs

 

이전 버전과 다르게 Route를 Routes로 감싸주어야 하며 보여줄 컴포넌트를 component={<컴포넌트 />}와 같이 작성해주어야 합니다.

 

 

[ Link 컴포넌트를 사용하여 다른 주소로 이동하기 ]

Link 컴포넌트는 클릭하면 다른 주소로 이동시켜 주는 컴포넌트입니다. 일반 웹 애플리케이션에서는 a 태그를 사용하여 페이지를 전환합니다. 하지만, 리액트 라우터를 사용할 때는 a 태그를 직접 사용하면 안 됩니다. 이 태그는 페이지를 전환하는 과정에서 페이지를 새로 불러오기 때문에 애플리케이션이 들고 있던 상태들을 모두 날려 버리게 됩니다. 이 경우 렌더링된 컴포넌트들도 모두 사라지고 다시 처음부터 렌더링 해야 합니다.

 

Link 컴포넌트를 사용하여 페이지를 전환하면, 페이지를 새로 불러오지 않고 애플리케이션은 그대로 유지한 상태에서 HTML5 History API를 사용하여 페이지의 주소만 변경해 줍니다. Link 컴포넌트 자체는 a 태그로 이루어져 있지만, 페이지 전환을 방지하는 기능이 내장되어 있습니다.

 

1
2
3
import { Link } from "react-router-dom";
 
  <Link to="주소"></Link>
cs

 

 

 

[ Route 하나에 여러 개의 path 설정하기 ]

Route 하나에 여러 개의 path를 지정하는 것은 최신 버전의 리액트 라우터 v5부터 적용된 기능입니다. 이전 버전에서는 여러 개의 path에 같은 컴포넌트를 보여주고 싶다면 다음과 같이 해야 했습니다.

 

1
2
<Route path='/about' component={About} />
<Route path='/info' component={About} />
cs

 

이렇게 Route를 두 번 사용하는 대신, path props를 배열로 설정해 주면 여러 경로에서 같은 컴포넌트를 보여줄 수 있습니다. 

 

1
2
3
{["/about""/info"].map((path) => (
       <Route path={path} key={path} element={<About />/>
 ))}
cs

 

 

 

[ URL 파라미터와 쿼리 ]

페이지 주소를 정의할 때 가끔은 유동적인 값을 전달해야 할 때도 있습니다. 이는 파라미터와 쿼리로 나눌 수 있습니다. 

 

파라미터 예시: /profile/velopart 

 

쿼리 예시: /about? details=true

 

유동적인 값을 사용해야 하는 상황에서 파라미터를 써야 할지 쿼리를 써야 할지 정할 때, 무조건 따라야 하는 규칙은 없습니다. 다만 일반적으로 파라미터는 특정 아이디 혹은 이름을 사용하여 조회할 때 사용하고, 쿼리는 우리가 어떤 키워드를 검색하거나 페이지에 필요한 옵션을 전달할 때 사용합니다.

 

 

📌  URL 파라미터

다음 예시를 확인해 보겠습니다.

 

🧷 Profile.js 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import React from 'react';
import { useParams } from 'react-router-dom';
 
const data = {
    velopart: {
        name'이정현',
        description: '리액트를 좋아하는 개발자'
    },
    gildong: {
        name'홍길동',
        description: '고전 소설 홍길동전의 주인공'
    }
};
 
const Profile = () => {
    const { username } = useParams();
    const profile = data[username];
    if(!profile) {
        return <div>존재하지 않는 사용자입니다.</div>
    } 
    return (
        <div>
            <h3>
                {username}({profile.name})
            </h3>
            <p>{profile.description}</p>
        </div>
    );
};
 
export default Profile;
cs

 

💡 useParams

리액트에서 라우터 사용 시 파라미터 정보를 가져와 활용하고 싶다면 useParams라는 훅을 사용해야 합니다. 참고로 파라미터가 아닌 현재 페이지의 Pathname을 가져오려면 useLocation()을 사용해야 합니다.

 

...URL/user/10 

user눈 pathname, 10은 parameter

 

🧷 Profiles.js

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import React from "react";
import { NavLink, Route, Routes } from "react-router-dom";
import Profile from "./Profile";
import WithRouterSample from "./WithRouterSample";
 
const Profiles = () => {
    const style = {
        background:'black',
        color:'white'
    };
  return (
    <div>
      <h3>사용자 목록:</h3>
      <ul>
        <li>
          <NavLink style={style} to="/profiles/velopart">velopart</NavLink>
        </li>
        <li>
          <NavLink style={style} to="/profiles/gildong">gildong</NavLink>
        </li>
      </ul>
      <Routes>
        <Route
          path="/profiles/*"
          element={() => <div>사용자를 선택해 주세요.</div>}
        />
        <Route path=":username" element={<Profile />/>
      </Routes>
      <WithRouterSample />
    </div>
  );
};
 
export default Profiles;
 
cs

 

Profiles.js에서

 

1
2
3
4
5
6
7
8
9
10
11
 <li> 
    <NavLink style={style} to="/profiles/velopart">velopart</NavLink>
 </li>
 
 <li> 
    <NavLink style={style} to="/profiles/gildong">gildong</NavLink> 
 </li>
 
// 생략
 
<Route path=":username" element={<Profile />/>
cs

 

NavLink를 통해 설정된 경로에 있는 velopart와 gildong이라는 username을 아래의 Route path를 통해 Profile.js에 전달됩니다.

 

이때 

 

1
const { username } = useParams();
cs

 

useParams()를 통해 username을 받아오게 됩니다. 

 

 

 

📌  URL 쿼리

쿼리는 useLocation()을 사용하여 조회할 수 있습니다. URL 쿼리는? detail=true&another=1과 같이 문자열에 여러 가지 값을 설정해 줄 수 있습니다. 이때 특정 값을 읽어 오기 위해서는 이 문자열을 객체 형태로 변환해 주어야 합니다.

 

쿼리 문자열을 객체로 변환할 때는 qs라는 라이브러리를 사용합니다.

아래는 yarn을 사용하여 해당 라이브러리를 설치하는 방법입니다.

 

yarn add qs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { useLocation } from "react-router-dom";
import qs from "qs";
 
const About = () => {
  const location = useLocation();
  const query = qs.parse(location.search, {
    ignoreQueryPrefix: true// 이 설정을 통해 문자열 맨 앞의 ?를 생략합니다.
  });
  const showDetail = query.detail === "true"// 쿼리의 파싱 결과 값은 문자열입니다.
  return (
    <div>
      <h1>소개</h1>
      <p>이 프로젝트는 리액트 라우터 기초를 실습해 보는 예제 프로젝트입니다.</p>
      {showDetail && <p>detail 값을 true로 설정하셨군요!</p>}
    </div>
  );
};
 
export default About;
 
cs

 

쿼리를 사용할 때는 쿼리 문자열을 객체로 파싱하는 과정에서 결과 값은 언제나 문자열이라는 것에 주의해야 합니다. 

 

?value=1 혹은 ?value=true와 같이 숫자나 논리 자료형(boolean)을 사용한다고 해서 해당 값이 우리가 원하는 형태로 변환되는 것이 아니라, '1','true'와 같이 문자열 형태로 받아집니다.

 

그렇기 때문에 숫자를 받아 와야 하면 parseInt 함수를 통해 꼭 숫자로 변환해 주고, 지금처럼 논리 자료형 값을 사용해야 하는 경우에는 정확히 "true" 문자열이랑 일치하는지 비교해야 합니다. 

 

 

 

[ 서브 라우트 ]

서브 라우트는 라우트 내부에 또 라우트를 정의하는 것을 의미합니다. 이 작업은 그렇게 복잡하지 않습니다. 그냥 라우트로 사용되고 있는 컴포넌트의 내부에 Route 컴포넌트를 또 사용하면 됩니다. 

 

 

📌 App.js

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import React, { Fragment } from "react";
import { Routes, Route, Link } from "react-router-dom";
import About from "./About";
import Home from "./Home";
import Profiles from "./Profiles";
import HistorySample from "./HistorySample";
 
function App() {
  return (
    <Fragment>
      <div>
        <ul>
          <li>
            <Link to="/"></Link>
          </li>
          <li>
            <Link to="/about">소개</Link>
          </li>
          <li>
            <Link to="/profiles">프로필</Link>
          </li>
          <li>
            <Link to="/history">History 예제</Link>
          </li>
        </ul>
      </div>
      <hr />
      <Routes>
        <Route path="/" element={<Home />/>
        {["/about""/info"].map((path) => (
          <Route path={path} key={path} element={<About />/>
        ))}
        <Route path="/profiles/*" element={<Profiles />/>
        <Route path="/history/*" element={<HistorySample />/>
        <Route
          path="/*"
          element={
            <div>
              <h2>이 페이지는 존재하지 않습니다.</h2>
            </div>
          }
        />
      </Routes>
    </Fragment>
  );
}
 
export default App;
 
cs

 

 

📌 Profiles.js 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import React from "react";
import { NavLink, Route, Routes } from "react-router-dom";
import Profile from "./Profile";
import WithRouterSample from "./WithRouterSample";
 
const Profiles = () => {
    const style = {
        background:'black',
        color:'white'
    };
  return (
    <div>
      <h3>사용자 목록:</h3>
      <ul>
        <li>
          <NavLink style={style} to="/profiles/velopart">velopart</NavLink>
        </li>
        <li>
          <NavLink style={style} to="/profiles/gildong">gildong</NavLink>
        </li>
      </ul>
      <Routes>
        <Route
          path="/profiles/*"
          element={() => <div>사용자를 선택해 주세요.</div>}
        />
        <Route path=":username" element={<Profile />/>
      </Routes>
      <WithRouterSample />
    </div>
  );
};
 
export default Profiles;
 
cs

 

 

📌 Profile.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import React from 'react';
import { useParams } from 'react-router-dom';
 
const data = {
    velopart: {
        name'이정현',
        description: '리액트를 좋아하는 개발자'
    },
    gildong: {
        name'홍길동',
        description: '고전 소설 홍길동전의 주인공'
    }
};
 
const Profile = () => {
    const { username } = useParams();
    const profile = data[username];
    if(!profile) {
        return <div>존재하지 않는 사용자입니다.</div>
    } 
    return (
        <div>
            <h3>
                {username}({profile.name})
            </h3>
            <p>{profile.description}</p>
        </div>
    );
};
 
export default Profile;
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
📌 App.js
 
 
<Route path="/profiles/*" element={<Profiles />/> // /profiles/*로 설정
 
 
 
📌 Profiles.js 
 
<Routes> 
    <Route path="/profiles/*" element={() => <div>사용자를 선택해 주세요.</div>}/> // /profiles/*로 설정
    
    <Route path=":username" element={<Profile />/> // :username과 같이 설정하며, /profiles/:username과 같이 작성하면 
</Routes>
 
 
cs

 

 

 

[ useNavigate() 사용하여 페이지 이동하기 ]

페이지 전환 시 추가로 처리해야 하는 로직이 있는 경우 useNavigate를 사용합니다.

 

 

1
2
3
4
5
6
7
8
9
import { useNavigate } from 'react-router-dom';
 
const navigate = useNavigate();
 
 
// 예시 
 
navigate(-1// 뒤로 가기
navigate('내가 가고싶은 주소 입력');
cs

 

 

[ NavLink ]

NavLink는 Link와 비슷합니다. 현재 경로와 Link에서 사용하는 경로가 일치하는 경우 특정 스타일 혹은 CSS클래스를 적용할 수 있는 컴포넌트입니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { NavLink } from "react-router-dom";
 
// 예시 1
 
  const style = {
        background:'black',
        color:'white'
    };
 
<NavLink style={style} to="이동할 주소"></NavLink>
 
 
// 예시 2 
 
import classes from './MainNavigation.module.css';
 
 <NavLink to="이동할 주소" className={({ isActive }) => isActive ? classes.active : undefined} end> </NavLink>
cs
Comments