Learning React(13. React 라우터를 이용한 싱글 페이지 앱 제작)

min seung moon·2021년 8월 17일
0

Learning React

목록 보기
13/15

1. 라우터를 이용한 싱글 페이지 앱 제

  • React는 SPA(Single Page Application)이기에 페이지가 로딩되거나 전환되는 것이 아닌 아닌 네비게이션을 통해서 뷰를 달리 보여주도록 해줍니다
  • 앱을 내비게이션하는 사용자가 기대 하는 것
      1. 주소 표시줄에 보이는 URL은 항상 지금 보고 있는 화면의 진짜 URL과 같아야 한다
      1. 브라우저의 이전 버튼과 다음 버튼을 사용할 수있어야 한다
      1. 정확한 URL을 사용해 특정 뷰(딥 링크deep link)를 바로 볼 수 있어야 한다
  • MPA(Multi Page Application)은 위에 3가지를 기본적으로 갖고 있지만, SPA는 새로 로딩(페이지 전환)하지 않기 때문에 사용자가 기대하는 3가지를 직접 구현해주어야 한다
  • 위의 과정을 처리하기 위해서는 라우팅(Routing)이라는 기법을 사용해야 한다
    • 라우팅은 URL을 물리적인 페이지가 아닌, 싱글 페이지 앱에서의 개별 뷰와 매핑하는 기법이다
    • 리액트에서 사용하기 위해서 리액트 라우터 라이브러리를 사용할 예정이다

01. 시작하기

  • create-react-app react_spa
    • cd react_spa
  • npm i react-router-dom --save
  • public과 src 폴더 안의 모든 파일들은 삭제하고 하나 하나 만들어보자!

-1. public / index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>React Router Example</title>
</head>

<body>
  <div id="root"></div>
</body>

</html>

-2. src / index.js

import React from "react";
import ReactDom from "react-dom";
import Main from "./Main";

ReactDom.render(<Main />, document.querySelector("#root"));

02. 앱 구축

-1. 초기 프레임 보여주기

  • SPA는 항상 정적으로 남아 있는 페이지의 일부가 존재한다
    • 이러한 정적인 부분을 앱 프레임(App Frame)이라고 한다
    • 앱 프레임은 모든 콘텐츠를 담는 컨테이너 역할의 HTML 엘리먼트이며 때때로 헤더, 푸터, 내비게이션 등을 포함하기도 한다

-2. src / Main.js

import React, { Component } from "react";

class Main extends Component {
  render() {
    return (
      <div>
        <h1>Simple SPA</h1>
        <ul className="header">
          <li>
            <a href="/">Home</a>
          </li>
          <li>
            <a href="/stuff">Stuff</a>
          </li>
          <li>
            <a href="/contact">Contact</a>
          </li>
        </ul>
        <div className="content"></div>
      </div>
    );
  }
}

export default Main;

-3. src / Home.js

import React, {Component} from 'react';

class Home extends Component{
  render() {
    return(
      <div>
        <h2>HELLO</h2>
        <p>
          Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ipsum rem natus veritatis, sapiente a quaerat eius autem enim minus! Sequi sapiente quisquam saepe officiis, eos minus harum nihil eius sint!
          Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ipsum rem natus veritatis, sapiente a quaerat eius autem enim minus! Sequi sapiente quisquam saepe officiis, eos minus harum nihil eius sint!
          Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ipsum rem natus veritatis, sapiente a quaerat eius autem enim minus! Sequi sapiente quisquam saepe officiis, eos minus harum nihil eius sint!
          Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ipsum rem natus veritatis, sapiente a quaerat eius autem enim minus! Sequi sapiente quisquam saepe officiis, eos minus harum nihil eius sint!
          Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ipsum rem natus veritatis, sapiente a quaerat eius autem enim minus! Sequi sapiente quisquam saepe officiis, eos minus harum nihil eius sint!
        </p>
        <p>
        Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ipsum rem natus veritatis, sapiente a quaerat eius autem enim minus! Sequi sapiente quisquam saepe officiis, eos minus harum nihil eius sint!
        </p>
      </div>
    )
  }
}

export default Home;

-4. src / Stuff.js

import React, { Component } from "react";

class Stuff extends Component {
  render() {
    return (
      <div>
        <h2>Stuff</h2>
        <p>
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorem,
          dolor qui molestias repellat quaerat obcaecati aperiam consectetur
          veritatis sunt illum quod laudantium ratione laboriosam nostrum saepe,
          minus optio nihil temporibus.
        </p>
        <ol>
          <li>
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorem,
            dolor qui molestias repellat quaerat obcaecati aperiam consectetur
            veritatis sunt illum quod laudantium ratione laboriosam nostrum
            saepe, minus optio nihil temporibus.
          </li>
          <li>
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorem,
            dolor qui molestias repellat quaerat obcaecati aperiam consectetur
            veritatis sunt illum quod laudantium ratione laboriosam nostrum
            saepe, minus optio nihil temporibus.
          </li>
          <li>
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorem,
            dolor qui molestias repellat quaerat obcaecati aperiam consectetur
            veritatis sunt illum quod laudantium ratione laboriosam nostrum
            saepe, minus optio nihil temporibus.
          </li>
          <li>
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorem,
            dolor qui molestias repellat quaerat obcaecati aperiam consectetur
            veritatis sunt illum quod laudantium ratione laboriosam nostrum
            saepe, minus optio nihil temporibus.
          </li>
          <li>
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorem,
            dolor qui molestias repellat quaerat obcaecati aperiam consectetur
            veritatis sunt illum quod laudantium ratione laboriosam nostrum
            saepe, minus optio nihil temporibus.
          </li>
        </ol>
      </div>
    );
  }
}

export default Stuff;

-5. src / Contact.js

import React, {Component} from 'react';

class Contact extends Component {
  render() {
    return(
      <div>
        <h2>GOT QUESTIONS?</h2>
        <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Cupiditate aspernatur nihil sunt voluptatibus, soluta nulla excepturi eligendi, harum, voluptatum repellat nemo ullam quibusdam est impedit. Enim eum beatae accusamus aspernatur.</p>
      </div>
    )
  }
}

export default Contact;

-6. src / Main.js(리액트 라우터 사용하기)

_1. react-router-dom 추가

  • 리액트 라우터는 개발자가 라우팅 영역이라고 부르는 것을 정의함으로써 작동한다
    • 내비게이션 링크
    • 콘텐츠를 로딩하는 컨테이너
import { Route, NavLink, HashRouter } from "react-router-dom";
import Home from "./Home";
import Stuff from "./Stuff";
import Contact from "./Contact";

_2. react router 적용

  • HashRouter
    • HashRouter 컴포넌트는 내비게이션과 브라우저의 페이지 이력을 다루기 위한 기반을 제공
    • 내비게이션 링크를 정의해야 한다
    • 기존 a 태그를 NavLink 컴포넌트로 적용해보자
  • NavLink
    • NavLink 컴포넌트는 a 태그와 유사하다고 볼 수 있다
    • to 속성으로 정의된 이들 URL 값은 정확히 해당하는 콘텐츠를 로딩하기 위한 식별자 역할을 한다
    • 이는 Route 컴포넌트를 사용해 URL을 콘텐츠와 연결함으로써 내가 원하는 뷰를 보여줄 수 있다
  • Route
    • Route 컴포넌트에는 path라는 속성이 있다
    • path에 지정된 값은 이 라우팅이 활성화될 때 결정된다
    • 라우팅이 활성화되면 component 속성에서 지정한 컴포넌트의 렌더링이 시작된다
import React, { Component } from "react";
import { Route, NavLink, HashRouter } from "react-router-dom";
import Home from "./Home";
import Stuff from "./Stuff";
import Contact from "./Contact";

class Main extends Component {
  render() {
    return (
      <HashRouter>
        <div>
          <h1>Simple SPA</h1>
          <ul className="header">
            <li>
              <NavLink to="/">Home</NavLink>
            </li>
            <li>
              <NavLink to="/stuff">Stuff</NavLink>
            </li>
            <li>
              <NavLink to="/contact">Contact</NavLink>
            </li>
          </ul>
          <div className="content">
            <Route path="/" component={Home}></Route>
            <Route path="/stuff" component={Stuff}></Route>
            <Route path="/contact" component={Contact}></Route>
          </div>
        </div>
      </HashRouter>
    );
  }
}

export default Main;




03. 라우팅 문제 해결

  • 현재 위에 상황을 보면 Home 컴포넌트가 항시적으로 보여짐을 확인할 수 있다
  • 이는 Home 컴포넌트가 갖고있는 / 경로가 Stuff와 Contact의 경로와 겹치다 보니 Home이 항시적으로 부합이 되어 Home이 항시적으로 보이게 된것이다

-1. exact로 문제 해결

  • 이 문제를 해결하기 위해서 Home Route에 exact(정확한) 속성을 부여해준다
    • exact를 부여해주면 path가 정확하게 일치하는 경우에만 component를 보여주게 된다
import React, { Component } from "react";
import { Route, NavLink, HashRouter } from "react-router-dom";
import Home from "./Home";
import Stuff from "./Stuff";
import Contact from "./Contact";

class Main extends Component {
  render() {
    return (
      <HashRouter>
        <div>
          <h1>Simple SPA</h1>
          <ul className="header">
            <li>
              <NavLink to="/">Home</NavLink>
            </li>
            <li>
              <NavLink to="/stuff">Stuff</NavLink>
            </li>
            <li>
              <NavLink to="/contact">Contact</NavLink>
            </li>
          </ul>
          <div className="content">
            <Route path="/" exact component={Home}></Route>
            <Route path="/stuff" component={Stuff}></Route>
            <Route path="/contact" component={Contact}></Route>
          </div>
        </div>
      </HashRouter>
    );
  }
}

export default Main;




-2. src / index.css(CSS 추가)

  • 코드를 확인해보면 ul.header li a부분이 없다는 것을 확인할 수 있다
    • 그런데 적용은 된다? 그것은 NavLink가 a 태그와 동일하다는 것을 확인할 수 있다
    • <a aria-current="true" href="#/stuff">Home</a> 상태라고 보면 된다
  • 두번째 .active도 우리는 준적이 없지만 속성이 적용되어 있다
    • 이것도 마찬가지로 NavLink가 선택되면 toggle되는 속성이라고 볼 수 있다
    • <a aria-current="true" href="#/stuff" class="active" >Home</a> 상태라고 보면 된다
body{
  background-color: #FFCC00;
  padding: 20px;
  margin: 0;
}

h1, h2, p, ul, li {
  font-family: sans-serif;
}

ul.header li {
  display: inline;
  list-style: none;
  margin: 0;
}

ul.header {
  background-color: #111;
  padding: 0;
}

ul.header li a {
  color: #FFF;
  font-weight: bold;
  text-decoration: none;
  padding: 20px;
  display: inline-block;
}

.content {
  background-color: #FFF;
  padding: 20px;
}

.content h2 {
  padding: 0;
  margin: 0;
}

.content li {
  margin-bottom: 10px;
}

.active {
  background-color: #0099FF;
}

-3. src / index.js

import React from "react";
import ReactDom from "react-dom";
import Main from "./Main";
import "./index.css";

ReactDom.render(<Main />, document.querySelector("#root"));


profile
아직까지는 코린이!

0개의 댓글

관련 채용 정보