티스토리 뷰

반응형

React Router

React를 페이지를 분할하고 이동하기 위해 React Router를 사용법에 대해 알아보자. 버전5는 다른 블로그에 많이 있기 때문에 아래에서는 최신 버전인 React Router 버전 6을 사용하는 방법에 대해 알아보자.

 

 

// 프로젝트 적용버전
"react-router-dom": "^6.2.1",

// 라우터 적용가능 버전
React >= 16.8.

 

 

만약 버전 6을 설치했지만, 버전 5로 변경하고 싶은 경우에는 아래의 url을 보고 따라하면 버전5로 다운그래이드가 가능하다.

https://han-py.tistory.com/433

 

[react] router 버전 해결 (react-router-dom)

먼저 버전 문제를 살펴 보자. 그 후에 사용법을 적어본다. 0. 버전 문제 해결 최근 router가 버전 6으로 업그레이드가 됐다. 따라서 옛날 강의를 보는 사람들은 멘붕에 따졌을 것이라 생각한다. 왜

han-py.tistory.com

 

아래에 설명되어 있지 않은 추가기능은 아래의 url을 참고하자.

[Web/React] - react router 페이지 상단으로 올리기

 

 

기본환경

 create react app으로 프로젝트를 생성했다. 관련 내용은 아래의 url을 참고하고 이 블로그에서는 react router에 집중한다.

https://reactjs.org/docs/create-a-new-react-app.html

 

Create a New React App – React

A JavaScript library for building user interfaces

reactjs.org

 

설치

설치는 npm으로 간단히 가능하다.

npm install react-router-dom@6

 

React Router사용

import React from 'react';
import {
  BrowserRouter,
  Routes,
  Route,
} from "react-router-dom";
import Home from "./components/home";
import Invoices from "./components/invoices";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="invoices" element={<Invoices />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;
  • 위의 코드는 브라우저의 url과 컴포넌트를 연결하는 작업이다.
  • react-router-dom에서 BrowserRouter, Routes, Route를 가져와서 위와 같이 사용을 하면된다.
  • Route 부분의 path에 url을 적고 element에 컴포넌트를 넣으면 된다.
  • 특이한 점은 path뒤의 invoices 부분을 /invoices라 적지 않고 /를 빼고 적은 부분이라 할 수 있다.
  • element 부분도 이전과 다르게 {}내부에 컴포넌트를 포함해서 적어줘야한다.
  • BrowserRouter를 index.js에 적는 방법으로 소개된 글들도 있지만, BrowerRouter 태그가 Routes를 감싸주기만 하면 되기 때문에 크게 상관없다. 아래의 예제를 참고하자.

 

위의 코드부분을 아래와 같이 as를 이용해서 BrowserRouter를 Router로 이름만 변경해서 사용하기도 한다.

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";

function App() {
  return (
    <div className={styles.app}>
      <Router>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="portfolio" element={<Portfolio />} />
          <Route path="projects" element={<Hashtag />} />
        </Routes>
      </Router>
    </div>
  );
}

export default App;

 

만약 React Route에서 BowserRouter가 아닌 HashRouter로 변경하는 방법도 아래와 같이 하면된다. 필요에따라 변경해서 쓰면된다.

import { HashRouter as Router, Routes, Route } from "react-router-dom";

function App() {
  return (
    <div className={styles.app}>
      <Router>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="portfolio" element={<Portfolio />} />
          <Route path="projects" element={<Hashtag />} />
        </Routes>
      </Router>
    </div>
  );
}

export default App;

 

 

 

지금까지는 기본적인 React Route를 빠르게 사용하기 위한 사람들을 위한 설명이었다. 만약 조금 더 자세한 개념을 알고 싶다면 아래의 설명을 추가로 보면 좋을 것 같다.

 


 

index.js에서 적용

위의 코드는 App.js에서 적용을 한 코드이다. 아래는 src/index.js에서 적용한 코드이다. 위의 코드와 아래의 코드를 보면 알 수 있는것은 React router의 적용은 사용할 컴포넌트의 최상위에만 설정해주면 되는 것이지, 사용해야될 위치가 정해져 있는 것은 아니다. 보통은 아래와 같이 사용을 하고, index.js에 다른 로직들이 붙어서 길어지는 경우에는 App.js에 사용을 해주면 된다.

 

// index.js
import { render } from "react-dom";
import {
  BrowserRouter,
  Routes,
  Route,
} from "react-router-dom";
import App from "./App";
import Expenses from "./routes/expenses";
import Invoices from "./routes/invoices";

const rootElement = document.getElementById("root");
render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />} />
      <Route path="expenses" element={<Expenses />} />
      <Route path="invoices" element={<Invoices />} />
    </Routes>
  </BrowserRouter>,
  rootElement
);

 

추가 코드를 조금 더 적어보겠다. 위의 코드는 기본적으로 url을 설정하는 부분이다. 그리고 url을 설정 했으니 a태그와 같이 페이지를 이동할 수 있는 방법에 대해 알아보겠다.  Link를 불러와서 아래와 같이 사용한다.

// App.js
import { Link } from "react-router-dom";

export default function App() {
  return (
    <div>
      <h1>Bookkeeper</h1>
      <nav
        style={{
          borderBottom: "solid 1px",
          paddingBottom: "1rem",
        }}
      >
        <Link to="/invoices">Invoices</Link> |{" "}
        <Link to="/expenses">Expenses</Link>
      </nav>
    </div>
  );
}
  • nav 태그를 통해서 2가지 버튼을 누를 수 있도록 만들었다.
  • Link 태그의 to 속성은 위에서 index.js에서 설정해둔 url의 component가 보여지게 한다.
  • 아래는 위에서 불러올 컴포넌트를 만들어 준것이다.
// 각각의 컴포넌트는 아래와 같다
// src/routes/invoices.jsx
export default function Expenses() {
  return (
    <main style={{ padding: "1rem 0" }}>
      <h2>Expenses</h2>
    </main>
  );
}

// src/routes/expenses.jsx
export default function Invoices() {
  return (
    <main style={{ padding: "1rem 0" }}>
      <h2>Invoices</h2>
    </main>
  );
}

 

결과화면을 보면 아래와 같다.

 

 

기본 결과 페이지

 

invoices를 눌렀을 때 결과 페이지

  • 위의 결과를 보면 url 뒤에 index.js에서 설정한 url이 붙는 것을 확인 할 수 있다. 그리고 결과 페이지는 element에 설정한 컴포넌트인 것을 확인 할 수 있다.
  • Link 태그가 html의 a 태그와 유사한 것을 할 수 있다. 그리 link 태그의 to 속성에 index.js에서 설정한 path값을 넣어주면 되는 것을 확인 할 수 있다.

 

 

컴포넌트 내부에서 Route 부르기(<Outlet />)

위의 예시는 Link 태그 버튼을 누르면 페이지 전체가 이동한다. 하지만, 이제 App.js 내부에서 Link 태그 버튼을 누르면 페이지 내에서 컴포넌트만 변경되는 것들을 해보자. 하는 방법은 어렵지 않다. index.js에서 app Route 내부에 다른 Route를 포함시켜주고, <Outlet />을 추가하면된다. 

 

// index.js render 부분
// 변경전
const rootElement = document.getElementById("root");
render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />} />
      <Route path="expenses" element={<Expenses />} />
      <Route path="invoices" element={<Invoices />} />
    </Routes>
  </BrowserRouter>,
  rootElement
);


// 변경 후
const rootElement = document.getElementById("root");
render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />}>
        <Route path="expenses" element={<Expenses />} />
        <Route path="invoices" element={<Invoices />} />
      </Route>
    </Routes>
  </BrowserRouter>,
  rootElement
);

위의 내용을 보면, <Route path="/" element={<App />} /> 부분을 <Route path="/" element={<App />}></Route>로 닫는 태그를 추가하여 내부에 다른 Route 들을 넣어 준것을 알 수 있다. 그리고 App.jsx에 추가한 컴포넌트들을 보여줄 위치에 <Outlet /> 태그를 넣어주기만 하면된다.

 

// App.jsx
import { Outlet, Link } from "react-router-dom";

export default function App() {
  return (
    <div>
      <h1>Bookkeeper</h1>
      <nav
        style={{
          borderBottom: "solid 1px",
          paddingBottom: "1rem",
        }}
      >
        <Link to="/invoices">Invoices</Link> |{" "}
        <Link to="/expenses">Expenses</Link>
      </nav>
      <Outlet />
    </div>
  );
}
  • react-router-dom에서 Outlet을 불러온다. 그 후에 <Outlet /> 태그를 넣어주기만 하면된다. 그에 따른 결과값은 아래와 같다.

결과 화면을 보면 Outlet을 넣어준 위치에 컴포넌트에 적어준 내용이 포함되어 있는 것을 확인 할 수 있다.

 

 

 

데이터 React route로 보여주기

기본적으로 게시판의 url을 보면 /posts/1과 같이 마지막 url이 숫자로 이루어진 부분이 많다. 이러한 설정을 Link를 활용해서 해보자.

 

아래와 같이 데이터가 있다고 가정해 보자.

/**
 * @type {Invoice[]}
 */
let invoices = [
  {
    name: "Santa Monica",
    number: 1995,
    amount: "$10,800",
    due: "12/05/1995",
  },
  {
    name: "Stankonia",
    number: 2000,
    amount: "$8,000",
    due: "10/31/2000",
  },
  {
    name: "Ocean Avenue",
    number: 2003,
    amount: "$9,500",
    due: "07/22/2003",
  },
  {
    name: "Tubthumper",
    number: 1997,
    amount: "$14,000",
    due: "09/01/1997",
  },
  {
    name: "Wide Open Spaces",
    number: 1998,
    amount: "$4,600",
    due: "01/27/2998",
  },
];

export function getInvoices() {
  return invoices;
}

/**
 * @param {number} number
 * @returns {Invoice}
 */
export function getInvoice(number) {
  return invoices.find((invoice) => invoice.number === number);
}

/**
 * @param {number} number
 * @returns {void}
 */
export function deleteInvoice(number) {
  invoices = invoices.filter((invoice) => invoice.number !== number);
}

/**
 * @typedef {{ name: string; number: number; amount: string; due: string }} Invoice
 */
  • 데이터를 가져오려면 아래와 같이 getInvoices 함수를 호출하면 된다.
const invoices = getInvoices();

 

우선은 아래와 같이 Routes를 수정한다.

<Routes>
  <Route path="/" element={<App />}>
    <Route path="expenses" element={<Expenses />} />
    <Route path="invoices" element={<Invoices />}>
      <Route path=":invoiceId" element={<Invoice />} />
    </Route>
  </Route>
</Routes>
  • invoices Route 내부에 :invoiceId를 넣을것을 확인 할 수 있다.
  • invoiceId부분의 로직은 App 내부의 Invoices 내부의 invoiceId이다. 이렇게 내부에 넣으면 url이 뒤에 붙는다는 것을 확인 하면 된다.
  • :invoiceId 로 params 설정하는것을 확인하자.

 

 

아래와 같이 invoices.jsx를 수정하자.

import { Link } from "react-router-dom";
import { getInvoices } from "../data";

export default function Invoices() {
  let invoices = getInvoices();
  return (
    <div style={{ display: "flex" }}>
      <nav
        style={{
          borderRight: "solid 1px",
          padding: "1rem",
        }}
      >
        {invoices.map((invoice) => (
          <Link
            style={{
              display: 'block',
              margin: '1rem 0',
              backgroundColor: 'tomato',
            }}
            to={`/invoices/${invoice.number}`}
            key={invoice.number}
          >
            {invoice.name}
          </Link>
        ))}
      </nav>
    </div>
  );
}
  • getInvoices()를 import 해서 데이터를 가저온 것이다. 그리고 간단히 style을 넣어준거라 보면된다.
  • Link 태그 부분을 보면 클릭 시 /invoices/2 와 같이 url이 변경되도록 to 속성을 넣어주고, map을 사용했기 때문에 key에도 값을 넣어준 것을 알 수 있다.
  • style 범위가 헷갈리지 않도록 background-color를 추가해줬다. 결과값은 아래와 같이 나온다.

위의 붉은 색을 누르면 url이 지정한 값(ex_ localhost:3000/invoices/12)으로 변경되는 것을 알 수 있다. 그러나 빈화면이 뜬다. 왜냐하면 관련 url을 지정하지 않았기 때문이다. 아래와 같이 Outlet을 추가하면된다.

 

 

import { Outlet, Link } from 'react-router-dom';
import { getInvoices } from '../data';

export default function Invoices() {
  let invoices = getInvoices();
  return (
    <div style={{ display: 'flex' }}>
      <nav
        style={{
          borderRight: 'solid 1px',
          padding: '1rem',
        }}
      >
        {invoices.map((invoice) => (
          <Link
            style={{
              display: 'block',
              margin: '1rem 0',
              backgroundColor: 'tomato',
            }}
            to={`/invoices/${invoice.number}`}
            key={invoice.number}
          >
            {invoice.name}
          </Link>
        ))}
      </nav>
      <Outlet />
    </div>
  );
}

 

URL params 추가하기

위에서 못만든 invoice.jsx를 만들어주자.

import { useParams } from "react-router-dom";
import { getInvoice } from "../data";

export default function Invoice() {
  let params = useParams();
  let invoice = getInvoice(parseInt(params.invoiceId, 10));
  return (
    <main style={{ padding: "1rem" }}>
      <h2>Total Due: {invoice.amount}</h2>
      <p>
        {invoice.name}: {invoice.number}
      </p>
      <p>Due Date: {invoice.due}</p>
    </main>
  );
}
  • useParams()를 호출하면,  객체가 담긴다. 객체는 앞의 route에서 :로 설정한 값이 key로 담기고 url 뒷부분에 적혀진 값(:invoiceId)이 value로 들어온다. 위에서는 { invoiceId: '1995' } 이런 식으로 값이 들어갈 것이다. 
  • useParams로 가져온 값을 이용해서 데이터의 값들을 가져와서 뿌려주는 코드이다.
:invoiceId -> params.invoiceId

:invoiceId로 들어오는 숫자를 params.invoiceId로 불러온다고 보면된다.

 

 

값들을 누르면 아래와 같이 값이 표현됨을 알 수 있다.

 

 

 

404페이지 (React route)

개발자가 지정하지 않는 url을 셋팅해야할 필요성이 있다. 이러한 경우 404 페이지가 떠야하는데 현재는 빈화면이 뜬다. React route에서는 Route 태그에 path="*"을 설정하므로 관련 부분에 대한 핸들링이 가능하다. 아래와 같이 index.js에 넣어주면된다.

 

<Routes>
  <Route path="/" element={<App />}>
    <Route path="expenses" element={<Expenses />} />
    <Route path="invoices" element={<Invoices />} />
    <Route
      path="*"
      element={
        <main style={{ padding: "1rem" }}>
          <p>There's nothing here!</p>
        </main>
      }
    />
  </Route>
</Routes>
  • 위와 같이 path="*"을 넣어주고, element부분에 컴포넌트를 넣어주면, 된다. 생각보다 간단히 만들 수 있는 것을 확인 할 수 있다.

 

추가적인 react/nodejs에 관한 정보는 아래에서 참고하자.

 

[Web/nodejs] - nodejs 기초 총 정리

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
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
글 보관함