[react-router] 튜토리얼 - 경로 연결 -

김범식·2023년 8월 24일
0

React-Router-Dom

목록 보기
1/4
post-thumbnail

⭐ React Router란

React Router는 React 기반의 웹 애플리케이션에서 라우팅을 관리하기 위한 라이브러리 입니다. 라우팅은 사용자가 웹 내에서 다른 페이지로 이동하는 것을 말하며 React Router는 이를 쉽게 구현할 수 있도록 도와줍니다.

즉 SPA로 구성된 React 애플리케이션의 각컴포넌트를 URL 경로와 매핑시키는 방식으로 동작합니다.

설치

📎 npm 버전

npm install react-router-dom localforage match-sorter sort-by
npx create-react-app react-router-tutorial

react-router 공식문서에서 제공해주는 다음 코드를 넣으면 css나 비동기 서버통신을 미리 셋팅할 수 있습니다.

src/index.css

index.css file

src/contacts.js

contacts.js file

📎 최종 파일 구조

src
├── contacts.js
├── index.css
└── index.jsx

⭐ Router 추가하기

클라이언트 사이드 랜더링을 위해 다음코드를 추가해 줍시다.

📎 브라우저 라우터 생성 및 랜더링

src/index.js

import * as React from "react";
import * as ReactDOM from "react-dom/client";
import {
  createBrowserRouter,
  RouterProvider,<L
} from "react-router-dom";
import "./index.css";

const router = createBrowserRouter([
  {
    path: "/",
    element: <div>Hello world!</div>,
  },
]);

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

router변수에서 모든 라우팅을 세팅한다음 브라우저에 그리게 됩니다. 가장 기본적인 셋팅이기 때문에 처음에 이해가 가지 않는다면 우선은 받아들입시다.

해당 코드에서는 ‘/’라는 pathelement를 그리게 됩니다.

가장 기본적인 라우팅이라고 할 수 있다.

⭐ 루트경로

이 앱에서 전역 레이아웃을 추가해 봅시다.

다음경로에 파일을 추가적으로 만들어줍니다.

📎 루트 레이아웃 구성 요소 만들기

src/routes/root.jsx

export default function Root() {
  return (
    <>
      <div id="sidebar">
        <h1>React Router Contacts</h1>
        <div>
          <form id="search-form" role="search">
            <input
              id="q"
              aria-label="Search contacts"
              placeholder="Search"
              type="search"
              name="q"
            />
            <div
              id="search-spinner"
              aria-hidden
              hidden={true}
            />
            <div
              className="sr-only"
              aria-live="polite"
            ></div>
          </form>
          <form method="post">
            <button type="submit">New</button>
          </form>
        </div>
        <nav>
          <ul>
            <li>
              <a href={`/contacts/1`}>Your Name</a>
            </li>
            <li>
              <a href={`/contacts/2`}>Your Friend</a>
            </li>
          </ul>
        </nav>
      </div>
      <div id="detail"></div>
    </>
  );
}

다음과 같은 Root 컴포넌트를 만들고 아까 만든 “/”경로에 추가해 줍니다.

📎 루트경로 설정

scr/index.jsx

import { createBrowserRouter, RouterProvider } from "react-router-dom";
import Root from "./routes/Root";

// ahem
const router = createBrowserRouter([
  {
    path: "/",
    element: <Root/>, //해당경로에 컴포넌트 추가
  },
]);

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

‘/’경로가 아까 추가해둔 Root 컴포넌트로 변경되었습니다! 이제 라우팅을 어떻게 하면 좋을지 감이 오셨을 겁니다.

이번엔 your Name이라는 버튼을 한번 눌러봅시다.

http://localhost:3000/contacts/1 경로로 라우팅을 설정한적이 없기 때문에 에러가 발생합니다. 경고 메시지를 보니 errorElementErrorBoundary를 설정하라고 나옵니다.

해당 에러를 처리하기 위해 기본적인 오류페이지를 만들어 봅시다.

⭐ 찾을 수 없음 오류 처리

📎 오류페이지 만들기

src/error-page.jsx

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

export default function ErrorPage() {
  const error = useRouteError(); // 에러 발생 여부를 가져옵니다.
  console.error(error);

  return (
    <div id="error-page">
      <h1>Oops!</h1>
      <p>Sorry, an unexpected error has occurred.</p>
      <p>
        <i>{error.statusText || error.message}</i>
      </p>
    </div>
  );
}

📎 루트 경로에서 오류컴포넌트 연결

root 경로에 에러페이지를 추가해 줍시다

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

<Root/>에서 발생하는 모든에러는 <ErrorPage/>로 이동하게 됩니다.

이제 “/”경로에서 에러가 발생할 경우 다음과 같은 에러페이지가 화면에 나타나게 됩니다.

⭐ 연락처 경로 UI

이제 다른 페이지를 만들고 라우팅 해봅시다.

왼쪽 sidebar에 있는것이 연락처 목록입니다.

연락처 구성요소 UI 추가

src/routes/contact.jsx

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

export default function Contact() {
  const contact = {
    first: "Your",
    last: "Name",
    avatar: "https://placekitten.com/g/200/200",
    twitter: "your_handle",
    notes: "Some notes",
    favorite: true,
  };

  return (
    <div id="contact">
      <div>
        <img
          key={contact.avatar}
          src={contact.avatar || null}
        />
      </div>

      <div>
        <h1>
          {contact.first || contact.last ? (
            <>
              {contact.first} {contact.last}
            </>
          ) : (
            <i>No Name</i>
          )}{" "}
          <Favorite contact={contact} />
        </h1>

        {contact.twitter && (
          <p>
            <a
              target="_blank"
              href={`https://twitter.com/${contact.twitter}`}
            >
              {contact.twitter}
            </a>
          </p>
        )}

        {contact.notes && <p>{contact.notes}</p>}

        <div>
          <Form action="edit">
            <button type="submit">Edit</button>
          </Form>
          <Form
            method="post"
            action="destroy"
            onSubmit={(event) => {
              if (
                // eslint-disable-next-line no-restricted-globals
                !confirm(
                  "Please confirm you want to delete this record."
                )
              ) {
                event.preventDefault();
              }
            }}
          >
            <button type="submit">Delete</button>
          </Form>
        </div>
      </div>
    </div>
  );
}

function Favorite({ contact }) {
  // yes, this is a `let` for later
  let favorite = contact.favorite;
  return (
    <Form method="post">
      <button
        name="favorite"
        value={favorite ? "false" : "true"}
        aria-label={
          favorite
            ? "Remove from favorites"
            : "Add to favorites"
        }
      >
        {favorite ? "★" : "☆"}
      </button>
    </Form>
  );
}

어떤 구조로 되어있는지는 화면으로 살펴보고 붙여넣기 합니다.

📎 연락처 구성 요소 가져오기 및 새 경로 만들기

라우팅을 추가해 줍니다.

import Contact from "./routes/contact";

// 라우팅
const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    errorElement : <ErrorPage/>
  },
  {
    path: "contacts/:contactId",  //이경로로 이동하면 <Contact/> 가 보인다. 
    element: <Contact />,
  },
]);

해당 경로로 들어가면 귀여운 고양이가 보이게 됩니다.

여기서 :contactId파라미터가 됩니다. (1,2,3,”123”,…) 등 하나의 페이지에서 다양한 값이 필요할 때 사용됩니다. 자세한 내용은 뒤에 살펴봅시다.

이 페이지에는 하나의 문제점이 있습니다. Root컴포넌트 안에 존재하지 않는다는 것입니다. Root 컴포넌트와 경로가 다르기 때문에 sidebar는 더이상 보이지 않습니다. sidebar까지 함께 보이게 하기 위해 Root컴포넌트 안에 Contact를 넣어보도록 하겠습니다.

⭐ 중첩경로

연락처 경로를 루트경로의 자식으로 이동

코드를 다음과 같이 작성해 봅시다.

src/index.jsx

// 라우팅
const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    errorElement : <ErrorPage/>,
    children:[
      {
        path:"contacts/:contactId",
        element:<Contact/>
      }
    ]
  },

]);

아까와 달리 <Root/> 컴포넌트‘/’ 경로 밑에 <Contact/> 컴포넌트가 위치해 있습니다. 해당<Contact/> 컴포넌트를 사용하기 위해서는 <Outlet/>이라는 컴포넌트가 필요합니다.

📎 랜더링

src/routes/root.jsx

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

export default function Root() {
  return (
    <>
      {/* all the other elements */}
      <div id="detail">
        <Outlet />   // <Contact/>는 이곳에 위치하게 됩니다. 
      </div>
    </>
  );
}

Root 컴포넌트children의 컴포넌트가 다음 Outlet 컴포넌트에 위치하게 됩니다. 이제 실제 화면을 살펴 봅시다.

다음 경로에 Root컴포넌트Contact 컴포넌트가 모두 포함된걸 볼수있습니다!

⭐ 클라이언트 측 라우팅

이제까지의 코드에서는 사이드바에서 링크를 클릭하면 브라우저가 React Routrer를 사용해서 클라언트 라우팅을 하는게 아닌 URL에 대한 전체 문서요청을 수행해서 페이지를 그렸습니다. 이는 html css javascript를 전부 불러와야하기 때문에 자원낭비 심합니다.

이러한 문제를 해결하기 위해서 앞으로는 <Link/>를 사용해 URL을 업데이트해서 UI를 즉시 랜더링 할 수 있게 해봅시다.

수정하기전

					<ul>
              <li>
                <a href={`/contacts/1`}>Your Name</a>
              </li>
              <li>
                <a href={`/contacts/2`}>Your Friend</a>
              </li>
            </ul>

수정후

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

...
						<ul>
              <li>
                <Link to={`/contacts/1`}>Your Name</Link>
              </li>
              <li>
                <Link to={`/contacts/2`}>Your Friend</Link>
              </li>
            </ul>

이제페이지를 이동하는 과정에서 새로고침이 발생하지 않습니다. 클라이언트측에서 url를 업데이트하고 html css javascript를 전부 다시 가져오는것이 아닌 이미 받아온 정적 파일들로 화면을 즉시 만드는것이기 때문에 새로고침이 발생하지 않고 부드러운 페이지 전환이 가능해집니다.

react-router를 설치하고 router를 세팅하는 방법에 대해 알아보았습니다. 모든 자료는 react-router-dom 공식홈페이지에서 제공합니다.

profile
frontend developer

0개의 댓글