본문 바로가기
내일배움캠프/Today I Learned

[TIL 2023.06.23] React Router Dom (hooks, Dynamic route, useParam)

by 괴코딩 2023. 6. 23.

💻오늘 배운 내용

React Router Dom

페이지를 구현할 수 있게 해주는 패키지 (여러 페이지를 가진 웹을 만들 수 있게 된다)

 

패키지 설치

yarn add react-router-dom

 

react-router-dom 사용순서

  1. 페이지 컴포넌트 생성
  2. Router.js 생성 및 router 설정 코드 작성
  3. App.js에 import 및 적용
  4. 페이지 이동 테스트
// 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의 장점인 브라우저가 깜빡이지 않고 다른 페이지로 이동할 수 있게 만들어준다!

// path는 사용하고싶은 "주소"
// element는 해당 주소로 이동했을 때 보여주고자 하는 컴포넌트

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

export default Router;

 

Hooks

 

useNavigate

보내고자 하는 path로 페이지를 이동시킬 때 사용하는 hook

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

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

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

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

훅이 아니지만, 꼭 알아야 할 API 

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


JSX에서 a 태그를 사용해야 한다면, 반드시 Link 를 사용해서 구현해야 한다. 

왜냐하면 a 태그를 사용하면  페이지를 이동하면서 브라우저가 새로고침(refresh)되기 때문이다.

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;

 

Dynamic route

동적 라우팅이라고도 말하는데

path에 유동적인 값을 넣어서 특정 페이지로 이동하게끔 구현하는 방법을 말한다.

<Route path="works/:id" element={<Works />} />

path에 works/:id 라고 path가 들어간다. :id 라는 것이 바로 동적인 값을 받겠다라는 의미

:id 는 useParams 훅에서 조회할 수 있는 값이 된다.

 

useParam

path의 있는 id 값을 조회할 수 있게 해주는 hook

만약에 works/1로 이동하면 1 이라는 값을 주고, works/100으로 이동하면 100 이라는 값을 사용

예시)

// 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: '자바스크립트 배우기' },
];

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;

링크를 통해 이동한 페이지 내에서 param을 통해 id 조회 후 페이지 표시 ▽

// 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: '자바스크립트 배우기' },
];

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

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

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

export default Work;

 

❓발생한 이슈/고민

이전에 만들었던 Todo List에 React Router Dom을 활용하여 상세페이지를 추가로 구현하기

💡해결과정

shaed 폴더 생성 > Router.js 파일 생성 후

import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Home from 'pages/Home';
import Detail from 'pages/Detail';

const Router = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/detail/:id" element={<Detail />} />
      </Routes>
    </BrowserRouter>
  );
};

export default Router;

홈과 디테일 페이지의 라우터를 설정해주었다.

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

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

export default App;

app.js에서는 라우터 파일로 통하게 하고,

import React from 'react';
import '../App.css';
import styled from 'styled-components';
import Header from 'components/Header';
import Form from 'components/Form';
import List from 'components/List';
import Cappadocia from 'img/Cappadocia.jpg';

function Home() {
  return (
    <>
      <StSection />
      <StLayout>
        <Header />
        <Form />
        <List />
      </StLayout>
    </>
  );
}

export default Home;

const StSection = styled.section`
  background-image: linear-gradient(
      to right,
      rgba(185, 98, 239, 0.8),
      rgba(114, 166, 250, 0.8)
    ),
    url(${Cappadocia});
  background-size: cover;
  width: 100%;
  height: 300px;
  overflow: hidden;
  position: relative;
  z-index: 0;
`;

const StLayout = styled.div`
  max-width: 1200px;
  min-width: 800px;
  margin: 0 auto;
  display: flex;
  position: relative;
  top: -230px;
  background: none;
  flex-direction: column;
  align-items: center;
`;

home을 메인으로 두고 home에서 컴포넌트들을 뿌려주었다.

<StBtns>
  <Link to={`/detail/${item.id}`}>
    <StImg src={Detail} alt="상세보기" />
  </Link>
  <StDeleteBtn onClick={() => onClickDeleteBtn(item.id)}>
    <StImg src={Delete} alt="삭제버튼" />
  </StDeleteBtn>
</StBtns>

삭제버튼 옆에 상세보기 버튼을 추가하여 상세페이지로 이동하는 링크 API를 달아주었다.

import React from 'react';
import styled from 'styled-components';
import { useSelector } from 'react-redux';
import { useNavigate, useParams } from 'react-router-dom';

function Detail() {
  const params = useParams();
  const todos = useSelector((state) => state.todos.todos);
  const navigate = useNavigate();

  const foundTodo = todos.find((item) => {
    return item.id == params.id;
  });

  return (
    <StDiv>
      <StId>ID : {foundTodo.id}</StId>
      <StTitle>{foundTodo.title}</StTitle>
      <StP>{foundTodo.contents}</StP>
      <StBtn
        onClick={() => {
          navigate('/');
        }}
      >
        이전으로
      </StBtn>
    </StDiv>
  );
}

export default Detail;

일주일 간.....고생많았다...나야..

 

 

🧐궁금점과 부족한 내용

사실 상세페이지는 모달로 페이지 위에 띄우고 싶었는데

검색해보니 '리액트 라우터를 이용해서 간단하게 모달 만들기!' 이런 포스팅들도 많던데

나는 자꾸 오류가 나서 포기했다. 왜 안되는지 모르겠다. 오래 고민해봤지만 해결책을 못 찾아서..

할 일이 많아서 포기하고 넘어가지만 다음에 여유가 되면 다시 도전해보면 좋을 것 같다.

반응형