React Router 라이브러리

ssssm·2023년 7월 10일
post-thumbnail

이번 글에서는 리액트 라우터를 공부하며 알게 된 지식, 간단한 예제를 통해서 리액트 라우터 기본 사용 방법에 대해서 공유드리려고 합니다.

📌라우팅(Routing)?

새로운 URL 경로를 주소창에 입력 시 URL에 해당하는 새로운 페이지를 네트워크 서버상에 요청하게 되고, 서버는 새로운 HTML 파일을 받아와서 페이지 전체를 업데이트하게 됩니다.

이것은 웹 페이지의 이동 방법 중 하나이며, 웹 앱 형태 중 하나인 싱글 페이지 어플리케이션(SPA)에서 주로 사용되고 있습니다.

📌SPA(Single Page Application)?

페이지를 이동할 때마다 서버에 웹 페이지를 요청하여 새로 갱신하는 것이 아니라 미리 해당 페이지들을 받아 놓고, 페이지 이동 시 클라이언트의 라우팅을 이용하여 화면을 갱신하는 패턴을 적용한 웹앱입니다.

과거 웹 사이트는 지금과는 달리 하나의 HTML 파일에 전달되는 정보의 양이 적었습니다. 그래서 여러 페이지로 구성되었으며, 유저가 요청할 때 마다 페이지가 새로고침되면서 서버로부터 리소스를 전달받아 해석 후 렌더링이 이루어 졌습니다. HTML 파일, 웹 어플리케이션의 뷰가 어떻게 보여질지 서버에서 담당했죠.

하지만 기술이 점차 발전됨에 따라 한 페이지에 담긴 정보의 양이 매우 커졌고, 이는 서버에서 매번 새로운 페이지를 전송해주는 것이 점차 버거워 지게 되었습니다.

그래서 문제를 해결하기 위해 등장한 기술이 SPA입니다. 브라우저는 최초 한 번에 서버에 요청하여 전체를 로드하고, 이후부터는 변경 사항이 있는 특정 부분만 데이터를 전달받아 보여주죠. 이처럼 기존에 매번 서버에서 요청하여 서버가 페이지를 재렌더링을 하던 방식과 다른게 SPA의 특징입니다.

📌프로젝트 준비 & 라이브러리 설치

파일을 만들고 리액트 라우터를 사용할 프로젝트 생성.

$ yarn create react-app .

그리고 해당 프로젝트 디렉토리로 이동하여 리액트 라우터를 설치.

$ yarn add react-router-dom

📌라우터 생성

이렇게 하면 브라우저 라우터를 생성하고 첫 번째 경로를 구성하게 됩니다.

import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import './App.css';

const router = createBrowserRouter ([                  // 배열 형태
  {
    path: '/',
    element: <p>Home</p>,
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

export default App;


두 번째 경로 videos을 구성합니다.

import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import './App.css';

const router = createBrowserRouter ([
  {
    path: '/',
    element: <p>Home</p>,
  },
  {
    path: '/videos',
    element: <p>Videos</p>,
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

export default App;

만약 틀린 경로를 입력하면 Not Fount 페이지가 뜨는데요, 이런 경우에는 errorElement prop을 사용하면 내가 원하는 페이지로 만들 수 있습니다.

{
    path: '/',
    element: <p>Home</p>,
  	errorElement: <p>Not Found....</p>,
},

1. 폴더 구조

src 디렉토리에서 components와 pages 경로를 생성하세요.

components

  • 여러 페이지에서 공통으로 사용되는 컴포넌트 관리

pages

  • 라우팅에 필요한 것들

2. root Route 추가

(앱 전체 레이아웃) Root layout components 생성하세요.

// src/pages/Root/Root.jsx
import React from 'react';
import { Outlet } from 'react-router-dom';
import Navbar from '../../components/Navbar/Navbar';
import './Root.css';

export default function Root() {
    return (
        <div className='root'>
            <Navbar />
            <Outlet />
        </div>
    );
}

Root 경로로 설정 element

// src/App.js
import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import NotFound from './pages/NotFound';
import Root from './pages/Root/Root';


const router = createBrowserRouter ([
  {
    path: '/',
    element: <Root />,    
    errorElement: <NotFound />,
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

export default App;

3.root Route의 자식으로 이동

// src/App.js
import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import './App.css';
import NotFound from './pages/NotFound';
import Videos from './pages/Videos/Videos';
import Root from './pages/Root/Root';
import Weather from './pages/Weather/Weather';
import Home from './pages/Home/Home';

const router = createBrowserRouter ([
  {
    path: '/',
    element: <Root />,
    errorElement: <NotFound />,
    children: [
      { index: true, element: <Home/>},
      { path: '/videos', element: <Videos />},
      { path: '/weather', element: <Weather />},
    ],
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

export default App;

link 컴포넌트는 다른 주소로 이동시키는 컴포넌트입니다. 리액트 라우터를 사용할땐 <a href=''></a> 대신 <link to='/videos'></link>를 사용합니다.

a 태그의 기본적인 속성은 페이지를 이동시키면서, 전체 페이지를 새로 불러오게 됩니다. 그렇기 때문에 link 컴포넌트를 사용하는데요, HTML5 History API를 사용하여 브라우저의 주소만 바꿀 뿐, 페이지를 새로 불러오지는 않습니다.

// src/components/Navbar.jsx
import React from 'react';
import { Link } from 'react-router-dom';
import './Navbar.css';

export default function Navbar() {
    return (
        <nav className='nav'>
            <Link to='/'>Home</Link>
            <Link to='/videos'>Videos</Link>
            <Link to='/weather'>Weather</Link>
        </nav>
    );
}

📌상세페이지 구현 및 URL Params

다음은 URL 파라미터를 이용해서 상세페이지를 만드는 방법을 정리하겠습니다.

1. URL Parameters

http://localhost:3000/videos 경로의 특정 주제, 세부 페이지를 보여주고 싶은 경우가 있는데요.

이때 http://localhost:3000/videos/videoDetail와 같이 videos URL 뒤에 id를 넣어주면됩니다. 특정 아이디 혹은 이름을 조회할 때 주로 사용합니다.

일단 URL parameters를 사용하기 위해 <VideoDetail /> 컴포넌트를 추가하고, 경로 주소는 변수 videos/:videoId처럼 받을 수 있게 작성합니다.

// App.js
import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import './App.css';
import NotFound from './pages/NotFound';
import Videos from './pages/Videos/Videos';
import Root from './pages/Root/Root';
import Weather from './pages/Weather/Weather';
import Home from './pages/Home/Home';
import VideoDetail from './pages/VideoDetail/VideoDetail';

const router = createBrowserRouter ([
  {
    path: '/',
    element: <Root />,
    errorElement: <NotFound />,
    children: [
      { index: true, element: <Home/>},
      { path: '/videos', element: <Videos />},
      { path: '/videos/:videoId', element: <VideoDetail />},
      { path: '/weather', element: <Weather />},
    ],
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

export default App;

2. Videos 페이지에서 id로 URL 업데이트

// videos.jsx
import React, { useState } from 'react';
import './Videos.css';

export default function Videos() {
    const [text, setText] = useState('');
    const handelChange = (e) => {
        setText(e.target.value);
    }
    const handleSubmit = (e) => {
        e.preventDefault();
        setText('');
    }
    return <div className='videos'>Videos 페이지 입니다.
        <form onSubmit={handleSubmit}>
            <input type="text" placeholder='video id를 입력하세요' value={text} onChange={handelChange}/>
        </form>
    </div>;
}

이제 사용자가 해당 video id를 입력하고 enter를 치고 submit을 하면 해당 video 경로로 이동할 수 있습니다.

리액트 라우터에서 특정한 경로로 이동할 수 있는 방법은 두 가지 있습니다.

  1. 사용자가 <Link /> 태그에 명시된 to='/' 경로로 이동한다.
  2. 리액트 라우터의 useNavigate() Hook을 사용해서 동적으로 이동한다.

3. useNavigate()

// videos.jsx
import React, { useState } from 'react';
import './Videos.css';
import { useNavigate } from 'react-router-dom';

export default function Videos() {
    const [text, setText] = useState('');
    const navigate = useNavigate();              // 동적으로 이동
    const handelChange = (e) => {
        setText(e.target.value);
    }
    const handleSubmit = (e) => {
        e.preventDefault();
        setText('');
        navigate(`/videos/${text}`);
    }
    return <div className='videos'>Videos 페이지 입니다.
        <form onSubmit={handleSubmit}>
            <input type="text" placeholder='video id를 입력하세요' value={text} onChange={handelChange}/>
        </form>
    </div>;
}


다음 화면

4. useParams()

videos 페이지에서 videoId가 뭘로 입력됐는지 알 수 있습니다. 이때 사용하는 것이 useParams() 입니다.

// videoDetail.js
import React from 'react';
import './VideoDetail.css';
import { useParams } from 'react-router-dom';

export default function VideoDetail() {
    const { videoId } = useParams();
    return <div className='videoDetail'>videoDetail {videoId} 페이지입니당.</div>
}

console.log() 로 출력해보면 다음과 같습니다.

0개의 댓글