코딩/React

React Router Dom - 소개, hooks, children

junhub 2023. 4. 19. 22:04

# react-router-dom이란?

 

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

react-router-dom을 사용하면 여러 페이지를 가진 웹을 만들 수 있게 된다. 

 

 

 

# react-router-dom 설치하기

 

1. 패키지 설치

yarn add react-router-dom

 

 

 

# react-router-dom 사용하기

 

# 사용방법 순서

  1. 페이지 컴포넌트 생성
  2. Router.js 생성 및 router 설정 코드 작성
  3. App.js에 import 및 적용
  4. 페이지 이동 테스트

 

 

1. 페이지 컴포넌트 생성

Home, About, Contact, Works 라는 가상의 페이지, 총 4개의 컴포넌트를 만들어봤다.

src 폴더에 pages 라는 폴더를 만들고 그 안에 만들면 된다. 

 

 

 

2. Router.js 생성 및 route 설정 코드 작성

브라우저에 우리가 URL을 입력하고 이동했을 때 우리가 원하는 페이지 컴포넌트로 이동하게끔 만드는 부분이다.

URL 1개당 페이지 컴포넌트를 매칭해주는 것이고, 이 한개의 URL을 Route 라고 한다. 

 

그리고 Route들을 설정하는 코드는 Router.js 라는 파일을 별도로 분리해서 많이 작성하곤 한다. 

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

 

 

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;

 

 

 

 

이렇게 작성하면, Route 를 설정할 뼈대가 완성이 된 것

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.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 거치도록 코드를 구현해주는 것이다. 

 

 

 

 

 

# react-router-dom Hooks

 

# react-router-dom Hooks이란?

리액트에서도 useState와 같은 Hook을 제공하는 것과 같이 react-router-dom에서도 우리가 유용하게 사용할 수 있는 hook을 제공한다.  

 

 

# useNavigate

다른 페이지로 보내고자 할 때 사용할 수 있다. 위에서 테스트 했을 때 우리가 브라우저에 직접 path를 입력해서 페이지를 이동했었는데,

사실 사용자들이 브라우저에 path를 직접 입력해서 페이지를 이동하게 만드는 서비스는 거의 없을 것이다.

보통 어떤 버튼을 누르면 페이지로 이동하거나 또는 어떤 컴포넌트를 눌렀을 때 페이지를 이동하게 만드는데, 그럴 때 사용하는 훅이다. 

 

버튼의 클릭 이벤트 핸들러에 아래와 같이 코드를 작성하면 버튼을 클릭했을 때 우리가 보내고자 하는 path로 페이지를 이동시킬 수 있다. 꼭 버튼이 아니더라도, 컴포넌트의 클릭 이벤트 핸들러를 통해서 활용할 수 있다.

사용방법은 아래 코드와 같다. 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;

 

 

# children 용도

어떤 컴포넌트들은 어떤 자식 엘리먼트가 들어올지 미리 예상할 수 없는 경우가 있다.

범용적인 ‘박스’ 역할을 하는 Sidebar 혹은 Dialog와 같은 컴포넌트에서 특히 자주 볼 수 있다. 

여기서 말하는 범용적인 “박스” 역할을 하는 컴포넌트란 크게 봤을 때 Layout 역할을 하는 컴포넌트라고 생각해볼 수 있다.

children props를 찾아보시면 composition이라는 말을 많이 보게 될텐데 , composition은 합성이라는 의미가 있다고 한다. 

 

 

src/shared/Layout.js

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

어느 페이지를 가던 위의 레이아웃이 고정적으로 나오는 것을 알 수 있음

Router 컴포넌트 내부를 보면 <Layout></Layout> 형태로 내부 Route를 감싸고 있는데 만약 path가 '/'라면 Home 엘리먼트가 children 형태로 Layout에 내려가게 되고 

 

여기서 해당 엘리먼트의 렌더링 요소를 children으로 받아 미리 설정한 Header와 Footer 사이에 렌더링 하게된다. 

이때 <div style = {{...layoutStyles}}> 는 

 

이와 같이 미리 만들어 놓은 레이아웃 스타일을 가져와 children을 렌더링할때 스타일을 먹이겠다는 의미이다.

 

 

 

# 정리

  • react-router-dom을 이용하면, SPA 기반 인 리액트 프로젝트 안에서 여러개의 페이지를 구현할 수 있다.
  • Router.js에 Route 설정에 관련된 코드를 작성하고, 최상위 컴포넌트인 App.js에서 import 해서 사용한다.
  • react-router-dom는 여러가지 훅을 제공한다