본문 바로가기
강의/스파르타코딩클럽

[리액트 숙련주차] 2-19~20 React Router Dom (1), (2)

by gardenii 2023. 7. 1.

1. React Router Dom 이란?

- 페이지를 구현할 수 있게 해주는 패키지 

- routing 

2. React Router Dom 설치

yarn add react-router-dom

3. React Router Dom 사용하기

1. 페이지 컴포넌트 작성

- src 폴더에 pages 폴더를 만들고, 내부에 여러 페이지가 될 컴포넌트 파일을 만든다.

2. Router.js 파일 구현

- 브라우저에 url을 입력하고 이동했을 때 원하는 페이지 컴포넌트로 이동하게끔 만들어주기

-> 즉 url 1개당 페이지 컴포넌트를 매칭해주는 것 Route

- 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";

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;

3. App.jsx에 import

- 생성한 Router.js 컴포넌트를 App.jsx에 넣어주어 연결해줍니다.

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

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

export default App;

4. 테스트

- 프로젝트를 실행시키고, 브라우저 url에 /home, /about, /contact, /work 등을 입력하여 페이지 이동이 정상적으로 되는지 확인

4. React Router Dom Hooks

1. useNavigate

- 다른 페이지로 보내고자 할 때 사용

- 직접 path를 입력해서 이동하는 경우는 거의 X

- 보통 버튼이나 컴포넌트를 눌렀을 때 이동함 (ex. html a태그)

- 이벤트 핸들러에 코드를 작성하면 보내고자 하는 path로 이동시킬 수 있음

 

- useNavigate import
- onclick 내부 함수로 이동하고자 하는 navigete(" path ") 넣어줌

// 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;

2. useLocation

- 현재 위치하고 있는 페이지의 여러 정보를 추가적으로 얻을 수 있음

// 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;

3. Link

- 훅은 아니지만 꼭 알아야 할 API

- html의 a태그의 기능을 대체하는 API

- JSX에서 a태그를 사용해야 할 때, 반드시 Link를 사용해야 함

- a태그로 페이지를 이동하게 되면 새로고침되고, 렌더링되기 때문에 방지를 위함

 

- Link import 해주고, to 속성값으로 path를 넣어줌

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;

5. children 의 용도

- 어떤 컴포넌트들은 어떤 자식 엘리먼트가 들어올지 예상할 수 없을 수 있기 때문에, 점용적인 '박스' 역할을 하는 Sidebar, Dialog와 같은 컴포넌트에서 자주 볼 수 있음

- 주로 레이아웃 역할

- 레이아웃 컴포넌트의 children으로 Routes를 넣어주게 되면, Layout 컴포넌트의 내용은 고정된 상태로 아래 내용만 바뀌도록 할 수 있다.

// src/shared/Layout.js

import React from 'react';

// ~ styles ~

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 />
      // 헤더와 푸터 사이에 레이아웃의 children, 즉 Route를 넣어줌으로써 레이아웃 형태 구현 가능!
      <div style={{...layoutStyles}}>
        {children}
      </div>
      <Footer />
    </div>
  );
}

export default Layout;
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;

6. Dynamic Route

1. Dynamic Route란?

- 동적 라우팅

- path에 유동적인 값을 넣어 특정 페이지로 이동하게끔 하는 방법

2. Dynamic Route 설정하기

- Works 페이지에 여러 Work가 있고, 그것을 클릭했을 때 각각의 상세 페이지로 이동하게끔 구현하기

 

1. Work 컴포넌트 추가

// src/pages/Works.js

import React from "react";

const Works = () => {
  return <div>Works</div>;
};

export default Work;

 

2. Router.js 에서 Work 컴포넌트 추가하고(페이지 이동을 위해) path에 works/:id 를 넣어줌

- works/ 슬래시 뒤에 받고 싶은 파라미터(ex. :id)를 넣어, works/ 뒤에 어떤 링크가 올 때 Work 페이지로 이동하게끔 경로지정 해준 것

- ':id' 는 useParams 훅에서 조회할 수 있는 값이 됨

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 Work from "../pages/Work";

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

export default Router;

3. useParam

1. query parameter 조회하기

- useParam을 이용하면, Route의 element를 통해 같은 컴포넌트를 렌더링하더라도 각각의 param에 따른 고유한 값을 조회할 수 있음

 

2. Works.js 에서 각 id 값을 파라미터로 주어 이동시키기

- map으로 data를 출력할 때, data의 각 id를 키 값으로 지정

- data를 하나씩 출력해주고, data를 Link로 감싸주어 id 값을 파라미터로 준 뒤 각각의 상세페이지로 이동시킴 

// src/pages/Works.js

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

const data = [
  { id: 1, todo: '리액트 배우기' },
  { id: 2, todo: '노드 배우기' },
  { id: 3, todo: '자바스크립트 배우기' },
  { id: 4, todo: '파이어 베이스 배우기' },
  { id: 5, todo: '넥스트 배우기' },
  { id: 6, todo: 'HTTP 프로토콜 배우기' },
];

function Works() {
  return (
    <div>
      {data.map((work) => {
        return (
          <div key={work.id}>
            <div>할일: {work.id}</div>
            <Link to={`/works/${work.id}`}>
              <span style={{ cursor: 'pointer' }}>➡️ Go to: {work.todo}</span>
            </Link>
          </div>
        );
      })}
    </div>
  );
}

export default Works;

 

3. 각각의 Work.js 에 useParams 훅 사용, find로 params와 비교

- useParams는 path에 있는 파라미터 값을 조회할 수 있도록 해주는 훅

- 지정한 path에서 어떤 파라미터로 이동할 때, 어떤 파라미터를 이용해 이동했는지 그 파라미터를 알게 해주는 역할!

- useParams 훅을 import 해주고, 사용하기 위해 param이라는 상수에 넣어줌

- find를 이용하여 data의 모든 요소들을 순회하며 useParam을 통해 조회된 파라미터 값이 들어있는 param의 파라미터 id값과, 각 data의 요소 하나를 뜻하는 work의 id 값이 일치하는 요소만 반환한 객체를 work에 넣어줌

- 그 후 return을 통해 파라미터와 동일한 data의 todo를 반환함

// src/pages/Work.js

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

const data = [
  { id: 1, todo: '리액트 배우기' },
  { id: 2, todo: '노드 배우기' },
  { id: 3, todo: '자바스크립트 배우기' },
  { id: 4, todo: '파이어 베이스 배우기' },
  { id: 5, todo: '넥스트 배우기' },
  { id: 6, todo: 'HTTP 프로토콜 배우기' },
];

function Work() {
  const param = useParams();

  const work = data.find((work) => work.id === parseInt(param.id));

  return <div>{work.todo}</div>;
}

export default Work;

 

+) 반복되는 data 파일로 분리하기

- shared 폴더 아래에 data.js 파일을 생성하고, 내부에 data를 작성한 뒤 export해줌

// ../shared/data.js

export const data = [
  { id: 1, todo: '리액트 배우기' },
  { id: 2, todo: '노드 배우기' },
  { id: 3, todo: '자바스크립트 배우기' },
  { id: 4, todo: '파이어 베이스 배우기' },
  { id: 5, todo: '넥스트 배우기' },
  { id: 6, todo: 'HTTP 프로토콜 배우기' },
];

- data를 사용해야 하는 Work, Works 컴포넌트에 각각 import 하여 사용

- 아마 이런 data와 같은 것들은 나중에 중앙관리하거나 데이터베이스에서 가져와서 사용할 수 있는 것으로 추정

// src/pages/Works.js

import React from 'react';
import { Link, useParams } from 'react-router-dom';
import { data } from '../shared/data'

function Works() {
  return (
    <div>
      {data.map((work) => {
        return (
          <div key={work.id}>
            <div>할일: {work.id}</div>
            <Link to={`/works/${work.id}`}>
              <span style={{ cursor: 'pointer' }}>➡️ Go to: {work.todo}</span>
            </Link>
          </div>
        );
      })}
    </div>
  );
}

export default Works;
// src/pages/Work.js

import React from 'react';
import { useParams } from 'react-router-dom';
import { data } from "../shared/data";

function Work() {
  const param = useParams();

  const work = data.find((work) => work.id === parseInt(param.id));

  return <div>{work.todo}</div>;
}

export default Work;