프로그래밍 언어 | 컴퓨터 관련

[React] React Router v5 → v6 변경 내용 적용 예

영바이트 2021. 11. 15. 19:15

 

React Router를 사용해서 라우팅을 구현하는데 이전(v5) 문법들이 오류를 발생시켰다. React Router의 버전이 v6로 올라오면서 패키지의 크기가 작아지고 성능이 향상되었다. 그리고 사용 방법도 적지 않게 변경되었다. 그 내용들을 정리하려한다.

 

변경된 내용들은 이 글에서 다루는 것 보다 많다. 하지만 자주 사용하는 문법들을 중심으로 정리하려한다.

 

① <Switch>...</Switch> → <Routes>...</Routes>

 

② 'exact' keyword 없이 기본적으로 exact 매칭. URL 그룹은 'path/*'와 같이 * 와일드카드 문자 사용.

 

③ component={Component} → element={<Component/>}

 

④ <Redirect> → <Navigate> 예) <Navigate to="/home"/>

 

⑤ dynamic path(URL inline params) :+파라미터 이름, useParams hook 사용

 

코드를 보면서 위 각각의 예를 살펴보자.

※ 예제 코드는 이재승님의 『실전 리액트 프로그래밍(개정판)』에서 적당한 코드를 발췌하여 사용하였다.

 

아래 예제 코드에서 주석으로 처리되어 있는 부분이 이전(v5) React-Router 문법이고, 그 아래 행이 v6 문법이다.

 

▶ App.js

import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
import Rooms from './components/rooms';

function Home() {
  return (<h2>여기는 홈페이지입니다.</h2>);
}

function Photo() {
  return (<h2>여기서 사진을 감상하세요.</h2>);
}

function App() {
  return (
    <BrowserRouter>
      <div style={{ padding: 20, border: '5px solid gray' }}>
        <Link to="/">홈</Link>
        <br/>
        <Link to="/photo">사진</Link>
        <br/>
        <Link to="/rooms">방 소개</Link>
        <br/>
        {/* ① <Switch> */}
        <Routes>
          {/* <Route path="/" ② exact ③ component={Home}></Route> */}
          <Route path="/" element={<Home/>}></Route>
          <Route path="/photo" element={<Photo/>}></Route>
          {/* <Route path="/rooms" ③ component={Rooms}></Route> */}
          <Route path="/rooms/*" element={<Rooms/>}></Route>
        {/* ① </Switch> */}
        </Routes>
      </div>
    </BrowserRouter>
  );
}

export default App;

 

▶ components/rooms.js

import React from 'react';
import { Routes, Route, Link, useParams} from 'react-router-dom';

function Room() {
    // URL에 포함된 inline 파라미터를 usePrams hook을 이용해서 추출할 수 있다.
    const params = useParams();
    console.log('Rooms.js.params:', params);

    // React Router V6로 오면서 match 객체는 사용하지 않는다.
    // return (⑤ <h2>{`${match.params.roomId} 방을 선택하셨습니다.`}</h2>);
    return (<h2>{`${params.roomId} 방을 선택하셨습니다.`}</h2>);
}

function Rooms() {
    return (
        <div>
            <h2>여기는 방을 소개하는 페이지입니다.</h2>
            {/* <Link to={`${match.url}/blueRoom`}>파란 방입니다.</Link> */}
            <Link to='blueRoom'>파란 방입니다.</Link>
            <br/>
            {/* <Link to={`${match.url}/greenRoom`}>초록 방입니다.</Link> */}
            <Link to='greenRoom'>초록 방입니다.</Link>
            <br/>
            <h3>방을 선택해주세요.</h3>
            <Routes>
                {/* <Route path={`${match.url}/:roomId`} element={<Room/>}></Route> */}
                <Route path=':roomId' element={<Room/>}></Route>
                {/* <Route path='/rooms' render={() => <h3>방을 선택해주세요.</h3>}></Route> */}
            </Routes>
        </div>
    );
}

export default Rooms;

 

중첩 라우팅(nested routing)을 처리하는 방법이 v5에서 v6로 넘어오면서 조금 달라졌다. 이 부분 좀 더 살펴보자. App.js의 세번째 라우팅 패스 /rooms의 <Rooms/> 컴포넌트가 다시 라우팅 패스를 가지고 있다. v6 코드를 보면 상위 컴포넌트인 App에서 exact 매칭을 풀어주기 위해 * 와일드카드 문자를 사용해 /rooms/*와 같이 URL 그룹을 지정하고 있다.

 

▶ App.js

// ▶ v5
function App() {
  return (
    <BrowserRouter>
      <div style={{ padding: 20, border: '5px solid gray' }}>
        ... <Link>...</Link>들 ...
        <Switch>
          <Route path="/" exact component={Home}></Route>
          <Route path="/photo" component={Photo}></Route>
          <Route path="/rooms" component={Rooms}></Route>
        </Switch>
      </div>
    </BrowserRouter>
  );
}


// ▶ v6
function App() {
  return (
    <BrowserRouter>
      <div style={{ padding: 20, border: '5px solid gray' }}>
        ... <Link>...</Link>들 ...
        <Routes>
          <Route path="/" element={<Home/>}></Route>
          <Route path="/photo" element={<Photo/>}></Route>
          <Route path="/rooms/*" element={<Rooms/>}></Route>
        </Routes>
      </div>
    </BrowserRouter>
  );
}

 

v6를 사용하는 하위 컴포넌트(Rooms)에서는 상위 컴포넌트(App)에서 URL 그룹으로 지정한 /rooms/*에서 와일드카드 문자 *에 해당하는 부분만 추가로 라우팅하게된다. 예에서는 dynamic path를 사용했으므로 ':roomId'로 지정해주었다.

 

▶ /components/rooms.js

function Rooms({ match }) {
    return (
        <div>
            <h2>여기는 방을 소개하는 페이지입니다.</h2>
            <Link to={`${match.url}/blueRoom`}>파란 방입니다.</Link>
            <br/>
            <Link to={`${match.url}/greenRoom`}>초록 방입니다.</Link>
            <br/>
            <Routes>
                <Route path={`${match.url}/:roomId`} element={<Room/>}></Route>
                <Route path='/rooms' render={() => <h3>방을 선택해주세요.</h3>}></Route>
            </Routes>
        </div>
    );
}

function Rooms() {
    return (
        <div>
            <h2>여기는 방을 소개하는 페이지입니다.</h2>
            <Link to='blueRoom'>파란 방입니다.</Link>
            <br/>
            <Link to='greenRoom'>초록 방입니다.</Link>
            <br/>
            <h3>방을 선택해주세요.</h3>
            <Routes>
                <Route path=':roomId' element={<Room/>}></Route>
            </Routes>
        </div>
    );
}

 

포스팅 예제 코드 중 function Room()을 보면 useParams hook을 사용해서 Room 컴포넌트가 dynamic path인 :roomId값을 얻을 수 있다.

 

▶ components/rooms.js

function Room() {
    // URL에 포함된 inline 파라미터를 usePrams hook을 이용해서 추출할 수 있다.
    const params = useParams();
    console.log('Rooms.js.params:', params);

    // React Router V6로 오면서 match 객체는 사용하지 않는다.
    // return (<h2>{`${match.params.roomId} 방을 선택하셨습니다.`}</h2>);
    return (<h2>{`${params.roomId} 방을 선택하셨습니다.`}</h2>);
}

function Rooms() {
    return (
        ...
    );
}

export default Rooms;

 

아래 유튜브 클립에서 더 많은 정보들을 얻을 수 있다. 참고해 볼 만 한다.

https://www.youtube.com/watch?v=zEQiNFAwDGo