본문 바로가기
🕸웹/🟨JavaScript

리액트 라우터 개념과 설정 방법

by 캔 2024. 11. 25.

지난 글(https://lifewithcoding.tistory.com/282)에서 리액트는 SPA(Single Page Application)를 위한 라이브러리라고 설명했다. 즉, 리액트로 개발한 앱은 하나의 페이지 내에서 자바스크립트로 실행되며, 다른 내용을 보기 위해 버튼을 클릭해도 페이지 전체가 새로고침되지 않고 필요한 요소들만 재렌더링된다. 이는 SPA의 주요 특징 중 하나로, 부드럽게 페이지 내용을 변경할 수 있다는 장점이 있다. 하지만 몇 가지 문제점도 존재한다.

 

첫 번째로, 새로고침 시 처음 화면으로 돌아간다. SPA는 하나의 앱으로 동작하기 때문에 새로고침은 앱을 처음부터 다시 시작하는 것과 같다. 따라서 사용자가 앱과 상호작용하며 변경한 상태는 새로고침 시 초기화되고, 모든 작업을 처음부터 다시 시작해야 하는 불편함이 생길 수 있다.

 

두 번째로, 뒤로 가기 기능이 예상대로 작동하지 않는다. SPA에서는 기본적으로 하나의 URL에서 동작하기 때문에 라우팅을 구현하지 않으면 사용자가 뒤로 가기 버튼을 누를 경우 이전 사이트로 이동한다. 다시 웹 앱으로 돌아오더라도 새로고침과 동일한 문제가 발생하여 이전 상태를 잃고 처음 화면으로 돌아갈 가능성이 크다.

 

세 번째로, 라우팅이 구현되지 않은 경우 특정 상태를 즐겨찾기에 추가할 수 없다. SPA는 하나의 앱으로 동작하며, 라우팅이 구현되지 않으면 기본적으로 하나의 URL만 사용한다. 이로 인해 사용자가 특정 상태에서 즐겨찾기를 추가하더라도, 이후 해당 즐겨찾기를 통해 접속하면 항상 앱의 처음 화면으로 이동하게 된다.

 

이러한 문제들을 해결해 주는 도구가 바로 라우터이다. 리액트에서는 주로 react-router-dom이라는 라이브러리를 사용해 URL 경로를 관리함으로써 이러한 문제를 해결한다. 이를 통해 SPA에서도 다양한 페이지 상태를 표현할 수 있고, 사용자는 URL 변경과 함께 페이지가 전환되는 경험을 제공받는다. 결과적으로 일반적인 웹사이트처럼 뒤로 가기, 즐겨찾기 등의 기능도 정상적으로 작동하게 된다.

 

리액트 라우터로 경로와 컴포넌트 연결하기

스프링 프레임워크에서는 컨트롤러나 REST 컨트롤러에서 @RequestMapping("경로명"), @GetMapping("경로명"), @PostMapping("경로명") 등으로 경로를 설정하면 DispatcherServlet이 URL 경로에 따라 적절한 핸들러를 찾고, 핸들러 어댑터를 통해 요청을 처리하도록 한다. 이와 비슷하게 리액트에서는 클라이언트 사이드에서 react-router-dom과 같은 라이브러리를 사용해 라우팅을 구현한다.

 

아래 코드는 최상위 컴포넌트인 App(파일명은 App.js)이 라우터 컴포넌트를 포함한 JSX를 반환하는 것을 보여준다. 리액트에서 컴포넌트는 JSX를 반환하는 함수형 컴포넌트로 정의되며, 현재는 함수형 컴포넌트가 주로 사용되지만, 과거에는 클래스형 컴포넌트가 널리 사용되었다.

 

리액트에서 라우터를 설정할 때는 react-router-dom의 컴포넌트인 BrowserRouter(아래 코드에서는 별칭으로 Router 사용), Routes, Route를 사용한다. BrowserRouter는 브라우저의 히스토리 API를 활용해 페이지 새로고침 없이 URL 경로를 관리하고, SPA에서 URL 경로 변경에 따라 적절한 컴포넌트를 렌더링하며, 브라우저 내비게이션과 URL 동기화를 지원한다. 그 안에 Routes를 포함하고, 각 Route 컴포넌트가 경로와 렌더링할 컴포넌트를 매핑한다.

 

리액트 라우터를 사용하면 URL 경로를 컴포넌트와 매핑할 수 있어 SPA에서도 직관적인 내비게이션을 구현할 수 있다.

import React from "react";
import { Route, BrowserRouter as Router, Routes } from "react-router-dom";
import MyContextProvider from "./context/MyContextProvider";
import About from "./pages/About";
import Contact from "./pages/Contact";
import Form from "./pages/Form";
import Home from "./pages/Home";
import NotFound from "./pages/NotFound";

const App: React.FC = () => {
	return (
            <div>
                <Router>
                    <Routes>
                        <Route path="/" element={<Home />}></Route>
                        <Route path="/about" element={<About />}></Route>
                        <Route path="/form" element={<Form />}></Route>
                        <Route path="/contact" element={<Contact />}></Route>
                        <Route path="*" element={<NotFound />}></Route>
                    </Routes>
                </Router>
            </div>
    );
}

export default App;

 

Route 컴포넌트에서 경로명을 path에, 렌더링할 컴포넌트를 element에 설정하면, URL 변경 시 react-router-dom이 클라이언트 측에서 적절한 컴포넌트를 매핑해 렌더링한다. 이를 통해 SPA에서도 URL 경로에 따라 화면을 구성할 수 있으며, 일반적인 웹사이트처럼 동작하게 된다.

 

또한, React Router는 단순한 경로 매핑뿐 아니라 동적 경로 매칭과 URL 파라미터 처리 등의 고급 기능도 제공한다. 예를 들어, path="/users/:id"와 같이 동적 경로를 설정하면, 특정 사용자 ID에 따라 다른 컴포넌트를 렌더링할 수 있다. 이러한 기능은 사용자 맞춤 화면이나 데이터 기반 UI를 구현하는 데 유용하다.