본문 바로가기
JavaScript/React

React) 리액트 라우터로 SPA 개발하기 - 중첩된 라우트 (Outlet 컴포넌트, index props)

by 박채니 2022. 11. 23.
안녕하세요, 코린이의 코딩 학습기 채니 입니다.
[리액트를 다루는 기술]의 책을 참고하여 포스팅한 개인 공부 내용입니다.

 

리액트 라우터로 SPA 개발하기

 

중첩된 라우트

 

Articles.js

import { Link } from 'react-router-dom'

const Articles = () => {
    return(
        <ul>
            <li>
                <Link to="/articles/1">게시글 1</Link>
            </li>
            <li>
                <Link to="/articles/2">게시글 2</Link>
            </li>
            <li>
                <Link to="/articles/3">게시글 3</Link>
            </li>
        </ul>
    )
}

export default Articles;

 

Article.js

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

const Article = () => {
    const { id } = useParams();

    return (
        <div>
            <h2>게시글 {id}</h2>
        </div>
    )
}

export default Article;

useParams Hook을 이용해 파라미터 이름을 가져왔습니다.

 

App.js

import './App.css';
import Home from './pages/Home';
import About from './pages/About';
import { Routes, Route } from 'react-router-dom';
import Profile from './pages/Profile';
import Articles from './pages/Articles';
import Article from './pages/Article';

function App() {
  return (
    <Routes>
      <Route path='/' element={<Home />} />
      <Route path='/about' element={<About />} />
      <Route path='/profiles/:username' element={<Profile />} />
      <Route path='/articles' element={<Articles />} />
      <Route path='/articles/:id' element={<Article />} />
    </Routes>
  );
}

export default App;

해당 페이지들의 Route 설정을 해줍니다.

 

Home.js

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

const Home = () => {
    return (
        <div>
            <h1>홈</h1>
            <p>가장 먼저 보여지는 페이지입니다.</p>
            <ul>
                <li>
                    <Link to="/about">소개</Link>
                </li>
                <li>
                    <Link to="/profiles/chany">chany의 프로필</Link>
                </li>
                <li>
                    <Link to="/profiles/gildong">gildong의 프로필</Link>
                </li>
                <li>
                    <Link to="/profiles/void">존재하지 않는 프로필</Link>
                </li>
                <li>
                    <Link to="/articles">게시글 목록</Link>
                </li>
            </ul>
        </div>
    )
}

export default Home;

게시글 목록 페이지로 이동할 수 있도록 Home.js에 Link를 걸어줍니다.

이동도 잘 되고 출력도 잘 되는 것을 확인할 수 있습니다.

 

만일 각 게시글 하단에 게시글 목록을 표시해줘야한다면 어떻게 해아할까요?

ArticleList 컴포넌트를 새로 만들어 렌더링 해줄 수도 있지만, 중첩 라우트를 사용해 렌더링해줄 수도 있습니다.

 

App.js

import './App.css';
import Home from './pages/Home';
import About from './pages/About';
import { Routes, Route } from 'react-router-dom';
import Profile from './pages/Profile';
import Articles from './pages/Articles';
import Article from './pages/Article';

function App() {
  return (
    <Routes>
      <Route path='/' element={<Home />} />
      <Route path='/about' element={<About />} />
      <Route path='/profiles/:username' element={<Profile />} />
      {/* 수정 */}
      <Route path='/articles' element={<Articles />} >
        <Route path=':id' element={<Article />} />
      </Route>
    </Routes>
  );
}

export default App;

 

Articles.js

import { Link, Outlet } from 'react-router-dom'

const Articles = () => {
    return(
        <div>
            <Outlet />
            <ul>
                <li>
                    <Link to="/articles/1">게시글 1</Link>
                </li>
                <li>
                    <Link to="/articles/2">게시글 2</Link>
                </li>
                <li>
                    <Link to="/articles/3">게시글 3</Link>
                </li>
            </ul>
        </div>
    )
}

export default Articles;

Outlet 컴포넌트

- Route의 children으로 들어가는 JSX 엘리먼트를 보여주는 역할

 

Outlet 컴포넌트를 이용하여 Articles Route의 children인 Article를 보여주어 쉽게 처리할 수 있습니다.

 

공통 레이아웃 컴포넌트

 

이러한 Outlet 컴포넌트 속성을 이용하여 공통적으로 보여줘야 하는 레이아웃 또한 쉽게 보여줄 수 있습니다.

 

Layout.js

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

// 헤더 레이아웃
const Layout = () => {
    return (
        <div>
            <header style={{background: 'lightgray', padding: 16, fontSize: 24}}>
                Header
            </header>
            <main>
                <Outlet />
            </main>
        </div>
    )
}

export default Layout;

 

App.js

import './App.css';
import Home from './pages/Home';
import About from './pages/About';
import { Routes, Route } from 'react-router-dom';
import Profile from './pages/Profile';
import Articles from './pages/Articles';
import Article from './pages/Article';
import Layout from './Layout';

function App() {
  return (
    <Routes>
      <Route element={<Layout />}>  
        <Route path='/' element={<Home />} />
        <Route path='/about' element={<About />} />
        <Route path='/profiles/:username' element={<Profile />} />
      </Route>
      <Route path='/articles' element={<Articles />} >
        <Route path=':id' element={<Article />} />
      </Route>
    </Routes>
  );
}

export default App;

Home, About, Profile 컴포넌트에는 Header가 표시되도록 하였습니다.

따라서 해당 라우트들을 Layout 라우트와 중첩 시킨 후 Layout 컴포넌트에서 이들을 Outlet으로 표시해주었습니다.

 

index props

 

index props는 'path="/''와 동일한 의미를 가집니다.

 

App.js

function App() {
  return (
    <Routes>
      <Route path='/' element={<Layout />}>  
        <Route index element={<Home />} /
        
        ...
        ...

Home Route 컴포넌트를 path 대신 index로 표시해주었지만, '/' 경로에 들어가도 여전히 잘 표시됩니다.

상위 라우트의 경로와 일치하지만, 이후 경로가 주어지지 않았을 때 보여지는 라우트를 설정해주는 것이죠.

path="/"와 동일한 역할을 하지만 좀 더 명시적으로 표현하는 방법입니다.