[React] React Router 이용하기

김유진·2022년 6월 30일
1

React

목록 보기
7/64

다음 기능을 구현해보자.
1. 리액트 프로젝트에 라우터 적용하기
2. 페이지 컴포넌트 만들어보기
3. Route 컴포넌트로 특정 주소에 컴포넌트 연결해보기
4. Navbar을 생성하고, Link 컴포넌트를 이용하여 다른 페이지로 이동하고, Navbar을 페이지의 공통 레이아웃 컴포넌트로 만들기
5. URL 파라미터 사용하기
6. 쿼리 스트링 사용하기
7. 리액트 라우터 부가기능 살펴보기

1. 리액트 프로젝트에 라우터 적용하기

먼저 리액트 프로젝트에 라우터를 적용하려면 그에 대한 패키지를 깔아야 한다.
yarn create react-app react-study2
로 먼저 리액트 패키지를 깔고, 라우터 라이브러리도 설치해야 하니까 다음 명령어로 설치를 완료한다.
npm install react-router-dom@6
설치를 완료하면 package.json 파일에 들어가서 아래 내용을 확인한다.

{
  "dependencies": {
    "react-router-dom": "^6.3.0"
  }
}

그리고 브라우저라우터를 사용하기 위하여 index.js를 다음과 같이 고쳐 보자.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    < BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

요렇게 BrowserRouter로 감싸는 것~

2. 특정 페이지를 연결할 수 있는 컴포넌트 생성하기

우리가 페이지를 연결할 수 있는 Link에 대한 컴포넌트를 미리 만들어두어야 한다. 생성해보도록 하자.
src 폴더 밑에, pages라는 폴더를 새로 생성한다. 그리고 해당 폴더 안에 다음 파일들을 만들어 봅시다.
Home.js, Movie.js를 생성하고 해당 javascript 파일 안에 rsc를 입력하여 함수형 컴포넌트를 만들어둡시다.

Movie.js

import React from 'react';

const Movies = () => {
    return (
        <div>
            <h1>넷플릭스 영화 추천 목록</h1>
        </div>
    );
};

export default Movies;

Home.js

import React from 'react';

const Home = () => {
    return (
        <div>
            <h1>홈페이지입니다.</h1>
            <p>라우터 실습을 위하여 만들어봅시다.</p>
        </div>
    );
};

export default Home;

3. 라우터 컴포넌트로 특정 주소/페이지에 라우터 연결하기

라우터 연결은 다음 형식과 같이 이루어집니다.

<Route path = "주소규칙" element = {보여 줄 컴포넌트}/>

먼저 기본을 생성된 App.js 파일을 모두 삭제하고 다음과 같이 새로 적는다.

import React from 'react';
import { Routes , Route } from "react-router-dom";
import Home from './pages/Home';
import Movies from './pages/Movies';

const App = () => {
  return <Routes>
    <Route path ="/" element = {<Home />}></Route>
    <Route pahth ="/movies" element = {<Movies />}></Route>
  </Routes>
};

export default App;

실행시켜서 어떤 결과를 가지고 있는지 확인해보자.
Root 경로에는 Home 컴포넌트가 보이고, /Movies 경로에는 우리가 만든 Movie에 대한 컴포넌트가 보인다.

4. Navbar을 만들고 페이지를 이동해보자.

일단 pages 폴더에 Munubar.js라는 파일을 새로 만들어두자.
그리고 그곳에 다음과 같이 코드를 입력해보자.
Munubar.js

import React from 'react';

const Menubar = () => {
    return (
        <div>
            <ul>
                <li>Home</li>
                <li>Movies</li>
            </ul>
        </div>
    );
};

export default Menubar;

그리고 App.js파일에 가서 다음과 같이 수정하여보자.

import React from 'react';
import { Routes , Route } from "react-router-dom";
import Home from './pages/Home';
import Movies from './pages/Movies';
import Menubar from './pages/Menubar';

const App = () => {
  return <Routes>
    <Route path ="/" element = {<Home />}></Route>
    <Route path ="/movies" element = {<Movies />}></Route>
    <Route path ="/home" element = {<Menubar />}></Route>
  </Routes>
};

export default App;

이번에는 메뉴바의 요소를 눌러서 해당 컴포넌트로 이동해가는것을 실습해보자.
이 때 React Router의 link component를 사용해보자. html의 a태그와 기능이 비슷하지만, 페이지 전환을 방지한다는 특징이 있다.

다음과 같이 Link를 import하여 코드를 작성해볼 수 있다.
Menubar.js

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

const Menubar = () => {
    return (
        <div>
            <ul>
                <li>
                    <Link to = "/home">Home</Link>
                </li>
                <li>
                    <Link to = "/movies">Movies</Link>
                </li>
            </ul>
        </div>
    );
};

export default Menubar;

Link를 import한다는 것이 특징이다. 메뉴가 컴포넌트를 각각 불러오는 것은 비효율적이므로, 라우터의 중첩 경로를 이용하여 Menubar 가 공통적인 레이아웃이 되도록 설정하자.
App.js를 다음과 같이 다시 수정하자.

import React from 'react';
import { Routes , Route } from "react-router-dom";
import Home from './pages/Home';
import Movies from './pages/Movies';
import Menubar from './pages/Menubar';

const App = () => {
  return (
    <Routes>
      <Route path ="/" element = {<Menubar />}>
        <Route path ="/home" element = {<Home />}></Route>
        <Route path ="/movies" element = {<Movies />}></Route>
      </Route>
    </Routes>
  );
};

export default App;

중첩 경로를 사용하여 보이도록 한 것이다. 하위 경로를 지나다닐 때 상위 경로의 element까지 보이게 된다. 이로써 Menubar가 어디에서든지 보이도록 만들어지게 된 것이다. :) 하지만 이 때 하위 element는 상위 element에 가려 보이지 않으므로 outlet을 활용해야 한다.
App.js의 코드를 조금 더 수정해보도록 하자.

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

const Menubar = () => {
    return (
        <div>
            <ul>
                <li>
                    <Link to = "/home">Home</Link>
                </li>
                <li>
                    <Link to = "/movies">Movies</Link>
                </li>
            </ul>

            <Outlet/>
        </div>
    );
};

export default Menubar;

Outlet코드 하나 넣었을 뿐인데 하위 element도 방해 없이 잘 보이고 있음을 알 수 있다.

5. URL 파라미터 사용하기

우리가 페이지의 주소를 정의할 때는 유동적인 값을 정의할 때가 있다. 파라미터쿼리스트링으로 나뉘는데, 다음 특징을 함께 살펴보도록 하자.

  • URL 파라미터 예시 : /movies/1
    ex) 특정 아이디, 이름을 사용하여 조회할 때 사용한다.
  • 쿼리스트링 예시 : movies/1?detail=true
    ex) 키워드 검색, 페이지네이션, 옵션 전달시에 사용
    우리는 URL 파라미터를 사용하여 넷플릭스 영화를 추천하는 리스트를 만들어 보자.
    src 폴더 밑에 movies_data.js 파일을 만들어 그 안에 추천하고 싶은 영화 리스트를 작성해보도록 하자.
    movies_data.js
let movies = [
    {
      id: 1,
      title: "하울의 움직이는 성",
      director: "미야자키 하야오",
      category: "일본 애니메이션",
      detail:
        "아버지가 물려준 모자 기계를 지키는 수수한 소녀 소피. 전쟁도, 미녀의 심장을 노리는 마법사의 소문도 먼 세상 이야기일 뿐. 하지만 마녀의 저주로 할머니가 되면서, 소피의 인생이 회전목마처럼 힘차게 움직이기 시작한다.",
    },
    {
      id: 2,
      title: "보스 베이비2",
      director: "톰 맥그라스",
      category: "미국 애니메이션",
      detail:
        "각자의 삶을 살아가던 두 형제, 테드와 팀. 가족만 아는 비밀을 안고 이번엔 팀의 딸 티나와 힘을 합친다. 비열한 악당의 음모를 무너뜨리기 위해.",
    },
    {
      id: 3,
      title: "너의 이름은",
      director: "신카이 마코토",
      category: "일본 애니메이션",
      detail:
        "도쿄의 잘생긴 남자로 살아볼 순 없을까? 따분한 시골 생활에 질려 도시를 동경하는 여고생. 어느 날, 그 소원이 실제로 이루어진다. 도쿄의 남고생과 이따금 몸이 뒤바뀌는 것. 꿈결 같은 둘의 인연은 또 다른 운명을 부르기 시작한다.",
    },
    {
      id: 4,
      title: "아이 필 프리티",
      director: "마크 실버스틴",
      category: "미국 영화",
      detail:
        "난 왜 예쁘지 않은 걸까. 외모가 불만인 그녀, 스피닝 수업에서 아찔한 사고를 당한다. 깨어나보니 확 뒤집힌 그녀의 인생! 커리어도, 연애도 이젠 핑크빛이다!",
    },
    {
      id: 5,
      title: "트루먼쇼",
      director: "피터 위어",
      category: "미국 영화",
      detail:
        "한 사람의 일거수일투족이 24시간 생방송 되는 '트루먼 쇼'의 주인공 트루먼 버뱅크. 엄청난 인기를 끌고 있는 이 프로그램의 주인공인 자신만 이 사실을 전혀 모르고 있다. 모든 것이 방송이라는 것이 밝혀지면 그는 과연 어떤 선택을 할까.",
    },
    {
      id: 6,
      title: "아메리칸셰프",
      director: "존 패브로",
      category: "미국 영화",
      detail:
        "창의력이 지글지글 끓어오르는 셰프. 똑같은 메뉴만 고집하는 주인과 지지고 볶은 후 허름한 푸드트럭을 차리면서 맛깔나는 좌충우돌 여정에 오른다. 배고플 땐 보지 말 것!",
    },
    {
      id: 7,
      title: "인턴",
      director: "낸시 마이어스",
      category: "미국 영화",
      detail:
        "뜨거운 열정으로 단기간에 회사를 키워낸 30대 열혈 여성 CEO. 사별과 은퇴를 겪고 공허한 일상을 보내다가 새내기로 입사한 70세 남성 인턴. 문제없을까, 이 어색한 조합.",
    },
    {
      id: 8,
      title: "월요일이 사라졌다",
      director: "토미 비르콜리",
      category: "미국 영화",
      detail:
        "우리는 하나다! 엄격한 산아제한 정책을 시행하는 미래. 정부의 감시를 피해, 일곱 쌍둥이가 한 사람처럼 산다. 들킨 걸까? 사라진 자매 하나를 찾아, 여섯이 힘을 합친다.",
    },
  ];
  
  export function getMovies() {
    return movies;
  }
  
  export function getMovie(id) {
    return movies.find((movie) => movie.id === id);
  }

이제, 만들어진 data를 Movies.js컴포넌트에 넣어서 Map 함수로 띄워 보도록 해야 하는데, 각 영화에 대한 url ID를 이용하여 URL 파라미터를 생성해야 하므로 App.js에 다음 코드를 추가한다.

import Movie from './pages/Movie';

const App = () => {
  return (
    <Routes>
      <Route path ="/" element = {<Menubar />}>
        <Route path ="/home" element = {<Home />}></Route>
        <Route path ="/movies" element = {<Movies />}>
            <Route path = " :movieId" element = {<Movie />} />
        </Route>
      </Route>
    </Routes>
  );
};

export default App;

자, 이제 우리가 만든 영화데이터에 대한 목록을 나타낼 수 있게 하고, 이 링크를 눌렀을 때 주소값이 변하게 해봅시다.
Movies.js 파일로 들어가서 다음 코드를 작성해보세요.

import React from 'react';
import { getMovies } from '../movie_data';
import { Link, Outlet } from "react-router-dom";

const Movies = () => {
    const movies = getMovies();
    return (
        <div>
            <h1>넷플릭스 영화 추천 목록</h1>
            <div>
                {movies.map((movie) => (
                    <Link to = {`/movies/${movie.id}`} key = {movie.id} style = {{display : "block"}} >
                        {movie.title}
                    </Link>
                ))}
            </div>
			<hr />
            <Outlet />
        </div>
    );
};

export default Movies;

간단한 style도 적용을 해 보았는데, 먼저 movie_data.js 파일에 존재하는 모든 영화에 대한 정보를 받아오는 getMovies 함수를 import합니다. 그리고 map함수를 이용하여 해당 영화에 대한 값을 title로 풀어내 보여줍니다. 그 다음으로는 그 영화의 제목을 눌렀을 때 나타나는 링크를 변화시키기 위해, 그 링크를 영화의 id로 설정하였습니다. 이때 Link를 import하는 것을 까먹으면 안돼요~

여기서 주의해야 할 것은, Link to = ~ 쓸 때 ''가 아니라 `를 써야 한다는 것을 잊으면 안된다~ 이래서 자꾸 에러뜸 ㅎㅎ.

url 파라미터에 대해서 조금 더 공격적으로 알아보자.
Movie.js파일에 다음 코드를 작성해보자.

import React from 'react';

const Movie = () => {
    const params = useParams();
    
    return (
        <div>
            상세페이지입니다.
        </div>
    );
};

export default Movie;

여기서

const params = useparams()

에서의 params는 url 파라미터에서 사용되는 movie의 id값을 반환함을 알 수 있다.
즉, useParams는 url 파라미터에서 사용되는 값을 조회해 주는 친구라는 것을 알 수 있었네요 :)
이제 이를 이용하여, 조회된 파라미터 값과, 무비 데이터의 아이디 값이 같을 때, 해당 아이디의 다른 정보들도 가져올 수 있도록 코드를 가져오자.

movies_data.js파일에 이러한 코드가 있었다.

 export function getMovie(id) {
    return movies.find((movie) => movie.id === id);
  }

id를 가져오면 그 전체 영화에 대한 모든 값을 반환하는 함수이다
이 함수의 특징을 이용하여, 영화 id값에 따라서 영화에 대한 모든 정보를 수령하고, 그 수령한 정보에 대한 다른 정보들도 출력하여 보자.

import React from 'react';
import { useParams } from 'react-router-dom';
import { getMovie } from "../movie_data";

const Movie = () => {
    const params = useParams();

    const movie = getMovie(parseInt(params.movieId));

    
    return (
        <div>
            <h2>{movie.title}</h2>
            <p> 감독 : {movie.director}</p>
            <p> 카테고리 : {movie.category} </p>
        </div>
    );
};

export default Movie;

params값은 문자열이기 때문에 pareInt 메서드를 이용해주었다. 이제 상세페이지를 눌렀을때 그에 대한 제목, 감독, 카테고리가 뜬다. 우리가 params를 통하여 받은 값을 이용해, getmMovie 함수로 전체 함수에 대한 정보를 받아왔기 때문이다.

6. 쿼리스트링 이용하기

이번에는 쿼리스트링까지 이용하여 간략한 줄거리가 나오도록 해보자. 쿼리스트링은 url 파라미터와 달리 별도의 라우터를 사용하지 않아도 된다는 장점이 있다.
페이지의 정보를 알기 위해 useLocation을 사용해 보자. 영화의 제목을 누르면 콘솔창에 다음과 같이 뜬다.

이제, 링크에 다음과 같이 입력하여 보자. 그러면 콘솔창의 search에 다음과 같이 새로운 값이 입력된다.

이렇게 search 값 안에 '?detail=true' 값이 쿼리스트링 값으로 입력됨을 알 수 있다. 이렇게 쿼리스트링은 useLocationsearch값에서 찾아볼 수 있다.

이제 이 쿼리스트링을 파싱해보자.

const [searchParams, setSearchParams] = useSearchParams();

console.log(searchParams.get("detail"));

이렇게 파싱하면 console창에 true, false가 발생한다.
이제 자세히 보기 버튼을 누르고, 그 자세히 볼 내용이 등장하는 내용을 구성하여 보자!

클릭 이벤트 발생시에 쿼리 값이 변경되도록 해보자.

const detail = searchParams.get("detail");

    const handleClick = () => {
        setSearchParams({detail : detail == "true" ? false : true});
        console.log(detail);
    }

    
    return (
        <div>
            <h2>{movie.title}</h2>
            <p> 감독 : {movie.director}</p>
            <p> 카테고리 : {movie.category} </p>
            <button type = "button" onClick = {handleClick}>자세히 보기</button>
        </div>
    );
};

detail 변수를 추가하고, 이에 대한 이벤트 핸들러를 작성하여 버튼을 눌렀을 때 쿼리스트링 값이 변경되도록 한다.

이제 버튼 밑에 영화에 대한 간략한 소개를 붙여 보자.

    return (
        <div>
            <h2>{movie.title}</h2>
            <p> 감독 : {movie.director}</p>
            <p> 카테고리 : {movie.category} </p>
            <button type = "button" onClick = {handleClick}>자세히 보기</button>
            {detail === "true" ? <p>{movie.detail}</p> : " "}
        </div>
    );
};

짜잔, 결과는 다음과 같다.

7. 리액트 라우터 부가기능 살펴보기

① 라우터 경로로 지정하지 않은 페이지에 접속하였을때, 'NotFound' 페이지 만들기

App.js파일에 들어가 다음과 같이 작성해보자.

const App = () => {
  return (
    <Routes>
      <Route path ="/" element = {<Menubar />}>
        <Route path ="/home" element = {<Home />}></Route>
        <Route path ="/movies" element = {<Movies />}>
            <Route path = ":movieId" element = {<Movie />} />
        </Route>
      </Route>
      <Route path ="*" element = {<div>There's nothing here!</div>} />
    </Routes>
  );
};

없는 경로로 들어갔을 때 다음과 같은 문구가 뜬다.

Menubar.js 코드를 다음과 같이 수정하여 보자.

import { Link, Outlet,useNavigate } from "react-router-dom";
...
const Menubar = () => {
    const navigate = useNavigate();
    const goHome = () => {
        navigate("/");
    };

그리고 하단에 버튼을 하나 더 추가한다.

<button onClick = {goHome} type = "button"></button>

그럼 다음과 같이 아래 버튼을 클릭하면, 우리가 지정한 navigate("/"); 주소로 움직인다.

Link 대신에 NavLink를 사용하면 Link에서 사용하는 정보가 현재 라우터와 일치하는 경우 특정한 CSS를 제공할 수 있다.

import React from 'react';
import { getMovies } from '../movie_data';
import { NavLink, Outlet } from "react-router-dom";



const Movies = () => {
   const movies = getMovies();
   return (
       <div>
           <h1>넷플릭스 영화 추천 목록</h1>
           <div>
               {movies.map((movie) => (
                   <NavLink to = {`/movies/${ movie.id }`} 
                       key = {movie.id} 
                       style = {({isActive}) => {
                           return {
                               textDecoration : isActive ? "underline" : "",
                               color : isActive ? "#FF9#1B" : "",
                           };
                       }} 
                   >
                       <p>{movie.title}</p>
                   </NavLink>
               ))}
           </div>
           <hr />
           <Outlet />
       </div>
   );
};

export default Movies;

이렇게 작성하여 내가 선택한 영화를 눌렀을때, 주황색으로 밑줄 색이 바뀐다.

0개의 댓글