본문 바로가기

React

React Router로 SPA 개발하기

## 1. react-router-dom이란?

- **(1) 여러 페이지를 구현할 수 있게 해주는 패키지**
    
    `styled-components`, `redux` 에 이어서 또 하나의 패키지. 
    // 바로 `react-router-dom` 
   
웹사이트를 사용할 때 여러 페이지로 오가며 이동할 수 있는데,
`react-router-dom`을 배우면 여러 페이지를 가진 웹을 만들 수 있게 됨!

2. react-router-dom  설치하기
(1) 패키지 설치
vscode 터미널에서 아래 코드를 입력해서 패키지를 설치할 수 있음.

yarn add react-router-dom

**(2) 페이지 컴포넌트 생성**
1. 가상의 여러 페이지를 만들기. 
- `Home`, `About`, `Contact`, `Works`  총 4개의 컴포넌트를 만들기. 
`src` 폴더에 pages 라는 폴더를 만들고 그 안에 만들기. 
// 컴포넌트 안에 내용은 간단한 텍스만 넣어주기. (rfce 활용)
// 특별한 내용이 없이 단순히 컴포넌트의 이름만 JSX에 넣기


[중요] Router.js 생성 및 route 설정 코드 작성
브라우저에 우리가 URL을 입력하고 이동했을 때 우리가 원하는 페이지 컴포넌트로 이동하게끔 만드는 부분.
URL 1개당 페이지 컴포넌트를 매칭해주는 것.

1개의 URL을 Route 라고 함.
Route들을 설정하는 코드는 Router.js 라는 파일을 별도로 분리.

src안에 shared 라는 폴더를 생성해주고,
그 안에 Router.js 파일을 생성.

import React from "react";
// 1. react-router-dom을 사용하기 위해서 아래 API들을 import 

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

// 2. Router 라는 함수를 만들고 아래와 같이 작성합니다.
//BrowserRouter를 Router로 감싸는 이유는, 
//SPA의 장점인 브라우저가 깜빡이지 않고 다른 페이지로 이동할 수 있게 만들어줍니다!

const Router = () => {
  return (
    <BrowserRouter>
      <Routes>
      </Routes>
    </BrowserRouter>
  );
};

export default Router;

import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../pages/Home";
import About from "../pages/About";
import Contact from "../pages/Contact";
import Works from "../pages/Works";

const Router = () => {
  return (
    <BrowserRouter>
      <Routes>
				{/* 
						Routes안에 이렇게 작성합니다. 
						Route에는 react-router-dom에서 지원하는 props들이 있습니다.

						path는 우리가 흔히 말하는 사용하고싶은 "주소"를 넣어주면 됩니다.
						element는 해당 주소로 이동했을 때 보여주고자 하는 컴포넌트를 넣어줍니다.
				 */}
        <Route path="/" element={<Home />} />
        <Route path="about" element={<About />} />
        <Route path="contact" element={<Contact />} />
        <Route path="works" element={<Works />} />
      </Routes>
    </BrowserRouter>
  );
};

export default Router;

 // App.js에 Router.js  import 해주기
// 이렇게 생성한 Router 컴포넌트를  아래 코드와 같이 App.js에 넣어줍니다. 

import React from "react";
import Router from "./shared/Router";

function App() {
  return <Router />;
}

export default App;

// `Router.js`를 **App 컴포넌트에 넣어주는 이유는 
우리가 만든 프로젝트에서 가장 최상위에 존재하는 컴포넌트가 
App.js 이기 때문**//

// 어떤 컴포넌트를 화면에 띄우던, 
//항상 App.js를 거쳐야만 합니다. 
//그래서 path 별로 분기가 되는 `Router.js`  를 App.js에 위치시키고 
//우리의 서비스를 이용하는 모든 사용자가 항상 `App.js → Router.js` 거치도록 코드를 구현해주는 것

 

// useNavigate

// navigate 를 생성하고, navigate(’보내고자 하는 url’) 을 통해 페이지를 이동 시킬 수 있죠!
// src/pages/home.js

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

const Home = () => {
  const navigate = useNavigate();

  return (
    <button
      onClick={() => {
        navigate("/works");
      }}
    >
      works로 이동
    </button>
  );
};

export default Home;

 

 

 // useLocation
react-router-dom을 사용하면, 
우리는 우리가 현재 위치하고 있는 페이지의 여러가지 정보를 추가적으로 얻을 수 있습니다. 

이 정보들을 이용해서 페이지 안에서 조건부 렌더링에 사용하는 등, '
여러가지 용도로 활용할 수 있습니다.

// src/pages/works.js
import { useLocation } from "react-router-dom";

const Works = () => {
  const location = useLocation();
  console.log("location :>> ", location);
  return (
    <div>
      <div>{`현재 페이지 : ${location.pathname.slice(1)}`}</div>
    </div>
  );
};

export default Works;

// Link
Link 는 훅이 아니지만, 꼭 알아야 할 API
Link 는 html 태그중에 a 태그의 기능을 대체하는 API 입니다. 
만약 JSX에서 a 태그를 사용해야 한다면, 반드시 Link 를 사용해서 구현해야 합니다. 

왜냐하면 a 태그를 사용하면  페이지를 이동하면서 브라우저가 새로고침(refresh)되기 때문입니다. 
브라우저가 새로고침 되면 모든 컴포넌트가 다시 렌더링되야 하고, 
또한 우리가 리덕스나 useState를 통해 메모리상에 구축해놓은 모든 상태값이 초기화 됩니다. 

이것은 곧 성능에 악역향을 줄 수 있고, 불필요한 움직임입니다.
페이지를 이동시키고자 할때 useNavigate 또는 Link를 사용할 수 있게 됐습니다. 

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

const Works = () => {
  const location = useLocation();
  console.log('location :>> ', location);
  return (
    <div>
      <div>{`현재 페이지 : ${location.pathname.slice(1)}`}</div>
      <Link to="/contact">contact 페이지로 이동하기</Link>
    </div>
  );
};

export default Works;

// src/shared/Layout.js

import React from 'react';

const HeaderStyles = {
  width: '100%',
  background: 'black',
  height: '50px',
  display: 'flex',
  alignItems: 'center',
  paddingLeft: '20px',
  color: 'white',
  fontWeight: '600',
};
const FooterStyles = {
  width: '100%',
  height: '50px',
  display: 'flex',
  background: 'black',
  color: 'white',
  alignItems: 'center',
  justifyContent: 'center',
  fontSize: '12px',
};

const layoutStyles = {
  display: 'flex',
	flexDirection: 'column',
  justifyContent: 'center',
  alignItems: 'center',
  minHeight: '90vh',
}

function Header() {
  return (
    <div style={{ ...HeaderStyles }}>
      <span>Sparta Coding Club - Let's learn React</span>
    </div>
  );
}

function Footer() {
  return (
    <div style={{ ...FooterStyles }}>
      <span>copyright @SCC</span>
    </div>
  );
}


function Layout({ children }) {
  return (
    <div>
      <Header />
      <div style={{...layoutStyles}}>
        {children}
      </div>
      <Footer />
    </div>
  );
}

export default Layout;

src/shared/Router.js
import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Home from '../pages/Home';
import About from '../pages/About';
import Contact from '../pages/Contact';
import Works from '../pages/Works';
import Layout from './Layout';

const Router = () => {
  return (
    <BrowserRouter>
      <Layout>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="about" element={<About />} />
          <Route path="contact" element={<Contact />} />
          <Route path="works" element={<Works />} />
        </Routes>
      </Layout>
    </BrowserRouter>
  );
};

export default Router;

Dynamic Route 설정하기
Router.js이동해서 Dynamic Routes를 설정해봅시다.
Works 페이지에 여러개의 Work가 있고, 
그것을 클릭했을 때 각각의 상세페이지로 이동하게끔 구현해봅시다. 
일단 Work 라는 페이지가 먼저 있어야겠죠? Work 컴포넌트를 추가해주세요.
// src/pages/Work.js

import React from "react";

const Work = () => {
  return <div>Work는 하위페이지입니다.</div>;
};

export default Work;

그리고 이제 Router.js 이동해서 아래 코드를 추가

import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Home from '../pages/Home';
import About from '../pages/About';
import Contact from '../pages/Contact';
import Works from '../pages/Works';
import Layout from './Layout';
import Work from '../pages/Work';

const Router = () => {
  return (
    <BrowserRouter>
      <Layout>
        <Routes>
          {/* 
						Routes안에 이렇게 작성합니다. 
						Route에는 react-router-dom에서 지원하는 props들이 있습니다.

						path는 우리가 흔히 말하는 사용하고싶은 "주소"를 넣어주면 됩니다.
						element는 해당 주소로 이동했을 때 보여주고자 하는 컴포넌트를 넣어줍니다.
				 */}
          <Route path="/" element={<Home />} />
          <Route path="about" element={<About />} />
          <Route path="contact" element={<Contact />} />
          <Route path="works" element={<Works />} />
          <Route path="works/:id" element={<Work />} />
        </Routes>
      </Layout>
    </BrowserRouter>
  );
};

export default Router;

이전과는 다르게 path에 `works/:id` 라고 path가 들어갑니다. 
`:id` 라는 것이 바로 **동적인 값을 받겠다라는 의미입니다. 
그래서 works/1 로 이동해도 <Work /> 로 이동하고, `works/2`, `works/3` …. `works/100` 
모두 <Work /> 로 이동하게 해줍니다.**

그리고 `:id` 는 **useParams 훅에서 조회할 수 있는 값**