[React] SPA와 react-router-dom

youngseo·2022년 7월 28일
0

REACT

목록 보기
24/52
post-thumbnail

SPA와 react-router-dom

1. SPA

리액트는 Client Side Rendering 방식으로 동작하고, SPA를 만들 수 있도록 지원하는 라이브러리입니다.

리액트 공식문서에서는 SPA에 대해 아래와 같이 설명을 하고 있습니다.

싱글 페이지 애플리케이션(Single-page application, SPA)은 하나의 HTML 페이지와 애플리케이션 실행에 필요한 JavaScript와 CSS 같은 모든 자산을 로드하는 애플리케이션입니다. 페이지 또는 후속 페이지의 상호작용은 서버로부터 새로운 페이지를 불러오지 않으므로 페이지가 다시 로드되지 않습니다.

전통적인 방식의 웹 애플리케이션의 단점

전통적인 방식의 웹 애플리케이션은 여러개의 html페이지로 구성되어 있습니다. 어떤 웹사이트에 접속했을 때 서버는 해당하는 페이지를 보여줘야하는 HTML를 보내주게 됩니다.

초반에 웹어플리케이션은 static한 정보만 보여줬습니다. 하지만 점차 사용자의 인터렉션이 많아지고 동적인 데이터 요청도 많아졌습니다. 또한 웹성능도 계속해서 좋아지고 자바스크립트도 계속 발전했습니다.

  • 서버가 화면에 그리기 위한 html을 만들어서 내려주는 역할까지 담당하다보니 서버의 부담이 커졌습니다.
  • 속도가 느려졌습니다.
    • 정보의 양이 많아지며 서버에서 빠르게 정리해서 내려주기 위해서는 캐싱 등의 추가적인 작업도 필요했습니다.
  • 페이지를 이동할 때마다 새로운 html을 내려받기 때문에 이동 시, 깜빡임이 발생했습니다.

이런 배경을 바탕으로 url을 이동하더라도 새로운 HTML 을 서버에서 받지 말고 화면을 CIient 에서 그리자! (CIient Side Rendering)라는 아이디어가 나오겠습니다.

그런데 SPA로 웹 애플리케이션을 구축할 때 HTML 은 하나지만, 유저가 볼 수 있는 화면은 여러개여야 합니다. 따라서 라우팅 처리가 필연적으로 필요합니다.

라우팅

라우팅이란 URL 에 따라 알맞은 콘텐츠(UI)를 전달해주는 기능을 이야기합니다. 이러한 라우팅처리의 경우 History API를 통해 처리를 할 수 있습니다.
하지만 프로젝트의 크기가 커진다면 라우팅 처리도 커지기 때문에 보다 효율적인 처리를 위해 react-router라는 라이브러리를 사용합니다.

2. react-router

React Router는 React JavaScript 라이브러리 를 위한 가볍고 완전한 기능을 갖춘 라우팅 라이브러리입니다.
React Router 안에는 react-router,react-router-dom, react-router-native 패키지가 포함되어 있습니다.

  • react-router: react-router-dom 과 react-router-native 기능을 모두 포함하고 있는 패키지 입니다.
    • 즉, 웹개발을 위한 라우터 처리와 앱개발을 위한 라우터 처리가 모두 가능합니다.
  • react-router-dom : 웹 어플리케이션의 라우팅 처리를 위한 패키지 입니다.
    • 우리는 react-router-dom를 사용할 예정입니다.
  • react-router-native: 앱 어플리케이션 라우팅 처리를 위한 패키지 입니다.

2-1 세팅

$ yarn create react-app 파일명
$ cd 파일명
$ yarn add react-router-dom@6
$ yarn start

2-2 실습


react-router 공식문서

import {BrowserRouter, Routes, Route} from 'react-router-dom'
import MainPage from './components/MainPage'
import TechPage from './components/TechPage'
import BlogPage from './components/BlogPage'

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path={"/"} element={<MainPage />}></Route> 
        <Route path={"/tech"} element={<TechPage />}></Route>
        <Route path={"/blog"} element={<BlogPage />}></Route>
      </Routes>
    </BrowserRouter>
  )
}

export default App
  • react-router-dom에서 {BrowserRouter, Routes, Route}를 가져와 import 해줍니다.
  • BrowserRouter > Routes > Route 로 태크를 감싸줍니다.
  • BrowserRouter : 웹브라우저에서 react-router를 실행시키기 위한 인터페이스입니다.
    • 브라우저 주소에 보여지는 현재의 위치를 주소를 저장하고 navigate를 해줍니다.
    • 가장 최상위에 감싸야합니다.
  • Route에는 root url로 들어왔을 때 어떤 컴포넌트를 보여줄지를 설정해줄 수 있습니다.
    • <Route path={} element={}></Route>

2-3 링크구성하기

react-router에서는 a태그 대신 Link태그를 사용합니다.

  • <Link to=""></Link> 에서 to부분에 이동할 이동할 라우터를 적어줍니다.
  • 주의: Link 태그의 경우 App.js가 아닌 MainPage에서 사용이 됩니다.
import React from "react";
import { Link } from "react-router-dom"; //✅

export default function MainPage() {
  return (
    <div>
      <h1>MainPage</h1>
      <Link to="/blog">Blog</Link> |
      <Link to="/tech">Tech</Link> 
    </div>
  );
}

2-4 Nested Routes (중첩라우팅)

TechPage하위에 Javascript와 ReactPage가 위치하도록 구성해보도록 하겠습니다.

하위에 자식 라우터를 넣는 경우에는 닫는태그가 아니라 열고 닫는 태그를 사용해 그 사이에 라우터처리를 해주면 됩니다. 하지만 이번에는 api요청을 가장하며 static한 파일을 넣어 완성해보도록 하겠습니다.

App.js

import {BrowserRouter, Routes, Route} from 'react-router-dom'
import MainPage from './components/MainPage'
import TechPage from './components/TechPage'
import BlogPage from './components/BlogPage'
import Javascript from './components/JavascriptPage'
import ReactPage from './components/ReactPage'

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path={"/"} element={<MainPage />} />
        <Route path={"tech"} element={<TechPage />}>
          <Route path="javascript" element={<Javascript />} />
          <Route path="react" element={<ReactPage />} />
        </Route>
        <Route path={"blog"} element={<BlogPage />} />
      </Routes>
    </BrowserRouter>
  )
}

export default App

또한 이렇게 처리한 자식 라우터를 출력하기 위해서는 부모 컴포넌트에 Outlet처리를 해줘야합니다.

TechPage.js

import React from "react";
import { Outlet, Link } from "react-router-dom"; //1.✅

export default function TechPage() {
  return (
    <>
      <div>
        <h1>TechPage</h1>
        <Link to="/tech/react">React</Link> |{" "} //띄어쓰기
        <Link to="/tech/javascript">Javascript</Link>
      </div>
      <Outlet /> //2.✅
    </>
  );
}

2-5. Url Parameter

React와 JavScript페이지로 이동 시 해당하는 페이지의 글 리스트가 뜨도록 만들어보도록 하겠습니다.

각각의 페이지에서는 api호출을 통해 해당하는 글의 목록을 응답 받아 화면에 렌더링하게 됩니다.

ReactPage.js

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

function ReactPage() {
  const docs = [
    {
      id: 1,
      title: "React 공부를 시작하면서",
      date: "05/01/2021",
    },
    {
      id: 2,
      title: "CRA 없이 리액트 프로젝트 시작하기",
      date: "12/01/2021",
    },
    {
      id: 3,
      title: "이제는 사용해보자 useMemo & useCallback",
      date: "31/01/2021",
    },
    {
      id: 4,
      title: "React 프로젝트에 Prettier 적용하기",
      date: "15/02/2021",
    },
    {
      id: 5,
      title: "React의 setState() 제대로 사용하기",
      date: "28/02/2021",
    },
  ]
  return (
    <div>
      {docs.map((doc) => (
        <Link 
          key={doc.id} 
          to={`${doc.id}`} >{doc.title}
        </Link>
      ))}
    </div>
  )
}

export default ReactPage;

to={}에는 ${} 를 이용해 스트링 값으로 넣어줘야합니다.

라우팅 처리

이제 또 다시 중첩처리를 해줘야합니다. path는 :docId로 설정해줍니다.

App.js

import {BrowserRouter, Routes, Route} from 'react-router-dom'
import MainPage from './components/MainPage'
import TechPage from './components/TechPage'
import BlogPage from './components/BlogPage'
import Javascript from './components/JavascriptPage'
import ReactPage from './components/ReactPage'
import ReactDocPage from './components/ReactDocPage'

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path={"/"} element={<MainPage />}></Route>
        <Route path={"tech"} element={<TechPage />}>
          <Route path="javascript" element={<Javascript />} />
          <Route path="react" element={<ReactPage />} > //✅
            <Route path=":docId" element={<ReactDocPage />} /> //✅
          </Route> //✅
        </Route>
        <Route path={"blog"} element={<BlogPage />}></Route>
      </Routes>
    </BrowserRouter>
  )
}

export default App

해당하는 페이지 만들기

ReactDocPage.js

import React from "react";

export default function ReactDocPage() {
  // docID: 1, 2, 3....
 
  return (
    <div>
      ReactDocPage ##docId
    </div>
  );
}

Outlet처리

ReactPage.js

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

export default function ReactPage() {
  // api call -> react에 해당하는 글의 목록을 응답 받음.

  const docs = [
    {
      id: 1,
      title: "React 공부를 시작하면서",
      date: "05/01/2021",
    },
    {
      id: 2,
      title: "CRA 없이 리액트 프로젝트 시작하기",
      date: "12/01/2021",
    },
    {
      id: 3,
      title: "이제는 사용해보자 useMemo & useCallback",
      date: "31/01/2021",
    },
    {
      id: 4,
      title: "React 프로젝트에 Prettier 적용하기",
      date: "15/02/2021",
    },
    {
      id: 5,
      title: "React의 setState() 제대로 사용하기",
      date: "28/02/2021",
    },
  ];

  return (
    <div>
      {docs.map((doc) => (
        <Link
          to={`${doc.id}`}
          key={doc.id}
          style={{ display: "block", margin: "1rem 0" }}
        >
          {doc.title}
        </Link>
      ))}
      <Outlet />
    </div>
  );
}

ReactDocPage.js

해당하는 parmas가져오기

import React from "react";
import { useParams, useNavigate } from "react-router-dom";  //✅

export default function ReactDocPage() {
  // docID: 1, 2, 3....
  const params = useParams(); //✅

  const navigate = useNavigate();

  return (
    <>
      <div>ReactDocPage ##{params.docId}</div></>
  );
}

2-6 수정

특정 아이디 페이지로 이동 시 더이상 다른 react 리스트가 뜨지 않기를 원한다면 react의 자식컴포넌트가 아니라 형제 컴포넌트로 처리를 해주면 됩니다.

단, 형제컴포넌트로 설정을 할 때 to에 해당하는 주소 처리를 유의해야합니다.

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path={'/'} element={<MainPage />} />
        <Route path={'tech'} element={<TechPage />}>
          <Route path={'javascript'} element={<JavascriptPage />} />
          <Route path={'react'} element={<ReactPage />} />
          <Route path={'react/:docId'} element={<ReactDocPage />} />
        </Route>
        <Route path={'blog'} element={<BlogPage />} />
      </Routes>
    </BrowserRouter>
  );
}

2-7 로고를 이용한 home이동 처리

useNavigate를 이용해 로고를 누르는 경우 홈으로 이동하는 처리를 해줄 수 있습니다. 단, 이 useNavigate의 경우 라우트 컴포넌트 내에서만 설정이 가능합니다.

한번 ReactDocPage에 위치를 시켜보도록 하겠습니다.

import React from 'react';
import { useParams, useNavigate } from 'react-router-dom';

function ReactDocPage() {
  const params = useParams();
  const navigate = useNavigate();

  return (
  <>
    <h5 onClick={() => navigate("/")}>logo</h5>
    <div>ReactDocPage ##{params.docId}</div>
  </>
  )
}

export default ReactDocPage;

이렇게 navagate의 경우 링크 태그나, url을 통해 이동하는 것이 아니라 프로그래밍 적으로 페이지를 이동하는 경우 사용을 할 수 있습니다.

3. redirect

import Redirect from 'react-router-dom'

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" exact>
           <Redirect to="/welcome"/>
        </Route>
      </Routes>
    </BrowserRouter>
  )
}

리다이렉트를 하고자 하는 <Route>의 path경로를 path="/" exact로 바꿔줍니다. <Route></Route>태그 사이에 react-router-dom에서 제공하는 <Redirect />태그 안에 to속성을 이요애 어이도 이동할건지를 작성해줍니다.

0개의 댓글