React Router(v6) 사용하기

Teon·2022년 4월 26일
8
post-thumbnail

리액트 라우터(v6)를 사용해 아래와 같은 간단한 프로젝트를 만들어보겠습니다.

[미리보기]

1. 프로젝트 생성 및 라이브러리 설치

리액트 프로젝트 생성하기

$ yarn create react-app practice_router

라우터 라이브러리 설치하기

$ npm install react-router-dom@6

설치 확인하기
package.json에 react-router-dom이 잘 설치되어있는지 확인해봅시다.

"dependencies": {
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^13.0.0",
    "@testing-library/user-event": "^13.2.1",
    "react": "^18.0.0",
    "react-dom": "^18.0.0",
    "react-router-dom": "^6.3.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.0"
},

2. 프로젝트에 라우터 적용하기

React Router를 적용하기 위해선 가장 먼저 src/index.js 파일의 <App /> 컴포넌트를 <BrowserRouter>로 감싸줘야 합니다.

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

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

3. 필요한 컴포넌트 페이지 만들기

프로젝트 실습에 필요한 2개의 컴포넌트 페이지를 만들어 보겠습니다.

src폴더 밑에 pages폴더를 새로 생성하고 home.js와 movies.js 파일을 생성해주세요

📄pages/Home.js

import React from "react";

const Home = () => {
  return (
    <div>
      <h1>LIKELION React Course</h1>
      <p>리액트 라우터 실습 프로젝트입니다.</p>
    </div>
  );
};

export default Home;

📄pages/Movies.js

import React from "react";

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

export default Movies;

3. Route 컴포넌트로 특정 주소에 컴포넌트 연결하기

기존에 있는 App.js 안의 코드를 모두 삭제하고 함수형 컴포넌트로 새로 생성해줍니다.
📄App.js

import React from 'react';

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

export default App;

react-router-dom의 Routes와 Route 컴포넌트를 사용할 것입니다.
Routes안에 Route 컴포넌트를 사용합니다.

Route 사용법

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

Home과 Movies 컴포넌트를 각각 /home, /movies 주소로 연결해보겠습니다.

📄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 path="/movies" element={<Movies />} />
    </Routes>
  );
};

export default App;

각 주소로 접속했을 때 해당 컴포넌트가 잘 보이나요?
http://localhost:3000/
http://localhost:3000/movies

4. Navbar 만들고 Link 컴포넌트로 다른 페이지 이동하기

Navbar를 만들어 페이지를 이동해보도록 하겠습니다.

pages폴더에 Menubar.js 파일을 새로 만들어주세요
📄pages/Menubar.js

import React from "react";

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

export default Menubar;

Quiz )
App.js에 Menubar 컴포넌트를 import 시키고, Menubar 주소는 root로 Home의 주소는 '/home'으로 바꿔보세요

📄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 path="/movies" element={<Movies />} />
    </Routes>
  );
};

export default App;

Navbar의 목록들을 눌러 해당 컴포넌트로 이동하고 싶을 때는 React-router의 Link 컴포넌트를 사용하면 됩니다.

Link 사용법

<Link to =”주소”></Link>

기존에 a링크 쓰듯이 사용하면 됩니다.
a링크와 다른 점은 페이지 전환을 방지하는 기능이 내장되어 있다는 점입니다.

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

잘 이동되는지 확인해봅시다.

5. Navbar를 페이지들의 공통 레이아웃 컴포넌트로 만들기

Home과 Movies 페이지 위에 Navbar를 두어 페이지를 편하게 이동하도록 해보겠습니다.

물론, Home과 Movies 컴포넌트에 Menubar 컴포넌트를 각각 불러오는 방법도 있겠지만,
보여줘야 할 페이지들이 많아질 때는 비효율적일 것입니다.

따라서 저희는 Route의 중첩 경로를 이용하여 위의 기능을 구현해보겠습니다.

📄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 path="/movies" element={<Movies />} />
      </Route>
    </Routes>
  );
};

export default App;

상위 라우트는 Menubar를, 하위라우트는 Home과 Movies를 불러오도록 중쳡경로를 설정하였습니다.

실행화면을 보면 Home과 Movies 주소로 이동해도 Menubar만 보입니다.
상위 라우터 밑에 하위라우트의 element를 보여주고 싶을 때는 Outlet이라는 컴포넌트를 사용합니다.

📄pages/Menubar.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;

이제 실행화면을 다시 보면 각 경로별로 컴포넌트들이 잘 보여지게 됩니다.

여기서 잠깐
'/'(루트) 경로를 입력해보면 어떠한 하위라우트도 보여지고 있지 않습니다.
중첩 라우트를 사용할 때, 상위라우트에서 가장 먼저 보여질 하위라우트를 따로 지정해주는 것이 필요한데요.
이때는 index라는 props를 설정해주면 됩니다.

가장 먼저 보여질 하위라우트를 Home으로 설정해보겠습니다.
📄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 index element={<Home />} />
        <Route path="/movies" element={<Movies />} />
      </Route>
    </Routes>
  );
};

export default App;

이제 '/'루트 경로로 들어가면 Menubar와 Home 컴포넌트가 동시에 보이게 됩니다.
Home의 경로가 달라졌으니 Menubar에서 Link 컴포넌트로 지정해준 Home의 경로도 수정해주세요.
📄pages/Menubar.js

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

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

export default Menubar;

6. URL 파라미터 사용하기

페이지 주소를 정의할 때는 유동적인 값을 사용할 때도 있습니다.
이때는 파라미터와 쿼리 스트링으로 나뉩니다.

  • URL 파라미터 예시 : /movies/1
  • 쿼리스트링 예시 : /movies/1?detail=true

일반적으로 URL 파라미터는 특정 아이디 혹은 이름을 사용하여 조회할 때 사용하고,
쿼리스트링은 키워드 검색, 페이지네이션, 옵션 전달 등에 사용합니다.

6.1 데이터 생성

실습을 위해 src폴더 밑에 넷플릭스 추천 영화 데이터를 모아둘 movie_data.js파일을 생성해주세요.
📄src/movie_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:
      "우리는 하나다! 엄격한 산아제한 정책을 시행하는 미래. 정부의 감시를 피해, 일곱 쌍둥이가 한 사람처럼 산다. 들킨 걸까? 사라진 자매 하나를 찾아, 여섯이 힘을 합친다.",
  },
];

//movies 전체 데이터 조회
export function getMovies() {
  return movies;
}

6.2 상세 페이지 컴포넌트 만들기

Movies 컴포넌트 안에서 map함수를 이용해 data의 상세정보를 보여줄 것입니다.

이를 위해 pages폴더 안에 Movie 컴포넌트도 새로 생성해주세요
📄pages/Movie.js

import React from "react";

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

export default Movie;

6.3 URL 파라미터 경로 지정

URL 파라미터는 경로에 :을 사용하여 설정합니다.
📄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";
import Movie from "./pages/Movie";

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

export default App;

6.4 영화 목록 리스트 만들기

이제 Movies 컴포넌트에 movie_data를 불러오고, map함수를 이용해 영화 추천 리스트를 만들어보겠습니다.

📄pages/Movies.js

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

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;

/movies/1 , /movies/2와 같은 형태로 movie_data의 id값이 URL파라미터 주소 값으로 들어가게 됩니다. map을 사용할 땐 반드시 key값을 지정해줘야 하기 때문에 movie_data의 id값을 넘겨주었습니다.

영화 목록이 잘 뜨나요?

6.4 useParams

이번엔 영화 목록을 클릭했을 때 상세 페이지가 목록 밑에 뜨도록 해보겠습니다.

URL 파라미터는 useParams라는 Hook을 사용해 객체 형태로 조회할 수 있습니다.
아래와 같이 Movie.js를 수정 후, Console창을 봅시다.

📄pages/Movie.js

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

const Movie = () => {
  //URL 파라미터 사용하기
  const params = useParams();
  console.log(params);
  return <div>상세페이지입니다.</div>;
};

export default Movie;

/movies/1 일 경우 1을
/movies/2 일 경우 2를 출력합니다.

즉 useParams로 URL 파라미터의 값이 조회되는 것을 알 수 있습니다.

조회된 파라미터 값과 movie_data의 id값이 같을 때 해당 id의 다른 정보들도 가져올 수 있도록 해봅시다.

먼저 movie_data에 id로 하나의 영화 정보만 가져오는 함수를 추가해줍니다.
📄src/movie_data.js

...

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

📄pages/Movie.js

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

const Movie = () => {
  //URL 파라미터 사용하기
  const params = useParams();
  console.log(params);
  const movie = getMovie(parseInt(params.movieId));
  console.log(movie);

  return <div>상세페이지입니다.</div>;
};

export default Movie;

getMovie를 import 한 후, 조회된 파라미터 값을 인자로 넘겨줍니다.
주의할 점은 파라미터 값이 문자열이기 때문에 반드시 숫자로 바꿔줘야 합니다.

console창을 보면 조회된 파라미터 값에 따라 movie 객체가 잘 출력되는 것을 볼 수 있습니다.

이를 이용해 상세 페이지를 만들어보겠습니다.

6.5 영화 목록 클릭시 해당 영화 상세 페이지 띄우기

📄pages/Movie.js

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

const Movie = () => {
  //URL 파라미터 사용하기
  const params = useParams();
  console.log(params);
  const movie = getMovie(parseInt(params.movieId));
  console.log(movie);

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

export default Movie;

영화의 제목, 감독, 카테고리가 화면에 잘 보여지나요?

7. 쿼리 스트링 사용하기

이번에는 쿼리 스트링을 사용하여 '자세히'버튼을 눌렀을 때
?detail=true 이런 쿼리 스트링을 만들어 주어 영화의 간략한 줄거리가 나오도록 구현해보겠습니다.

쿼리 스트링은 URL파라미터와 달리 Route 컴포넌트를 별도로 설정하지 않아도 됩니다.

7.1 useLocation

먼저, 페이지의 정보를 알기 위해 useLocation이라는 Hook을 사용해보겠습니다.
📄pages/Movie.js

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

const Movie = () => {
  //URL 파라미터 사용하기
  const params = useParams();
  console.log(params);
  const movie = getMovie(parseInt(params.movieId));
  console.log(movie);

  //쿼리 스트링 사용하기
  const location = useLocation();
  console.log(location);

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

export default Movie;

console창을 보면 'pathname', 'search', 'hash', 'state', 'key'값들이 출력되고 있음을 알 수 있습니다.

이 상태에서 주소 창에
http://localhost:3000/movies/1?detail=true
처럼 입력한 후 콘솔창에 변화를 지켜보세요!

'search'에 ?를 포함한 쿼리스트링이 값으로 들어가 있음을 알 수 있습니다.

이렇게 쿼리스트링은 useLocation의 search값을 통해 조회가 가능합니다.

7.2 useSearchParams

이번에는 조회한 쿼리스트링을 파싱하여 자세히 버튼을 눌렀을 때는 detail 값에 true를 한 번 더 누르면 false 값을 주도록 하겠습니다.

쿼리스트링을 파싱할 때는 useSearchParams라는 Hooke을 사용합니다.

📄pages/Movie.js

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

const Movie = () => {
  //URL 파라미터 사용하기
  const params = useParams();
  console.log(params);
  const movie = getMovie(parseInt(params.movieId));
  console.log(movie);

  //쿼리 스트링 사용하기
  const location = useLocation();
  console.log(location);

  const [searchParams, setSearchParams] = useSearchParams();
  console.log(searchParams.get("detail"));

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

export default Movie;

useSearchParams의 get은 쿼리파라미터를 조회하고, set메서드는 특정 쿼리파라미터를 업데이트 할 수 있습니다.

아직 주소창에
http://localhost:3000/movies/1?detail=true
이 입력되어 있나요?

현재 console창에 "detail" 쿼리 파라미터의 값을 반환하도록 하였더니 'true'라는 값이 잘 출력되는 모습을 볼 수 있습니다.

7.2 자세히 버튼 만들고 이벤트 생성하기

이제 useSearchParams와 useLocation을 이용해 자세히 보기 버튼을 만들고, 클릭 이벤트 발생 시 "detail"쿼리 파라미터의 값이 변경되도록 만들어보겠습니다.

📄pages/Movie.js

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

const Movie = () => {
  //URL 파라미터 사용하기
  const params = useParams();
  //console.log(params);
  const movie = getMovie(parseInt(params.movieId));
  //console.log(movie);

  //쿼리 스트링 사용하기
  const location = useLocation();
  //console.log(location);

  const [searchParams, setSearchParams] = useSearchParams();
  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 onClick={handleClick} type="button">
        자세히
      </button>
    </div>
  );
};

export default Movie;

버튼을 누를 때마다 detail의 값이 잘 바뀌나요?

이제 삼항 연산자를 이용해 detail 값이 true 면 보이고 아니면 보이지 않게 하겠습니다.
주의할 점은 detail안에 저장된 파라미터의 true값은 문자열 이기 때문에 비교시 꼭 " "로 묶어줘야 합니다.

📄pages/Movie.js

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

const Movie = () => {
  //URL 파라미터 사용하기
  const params = useParams();
  //console.log(params);
  const movie = getMovie(parseInt(params.movieId));
  //console.log(movie);

  //쿼리 스트링 사용하기
  const location = useLocation();
  //console.log(location);

  const [searchParams, setSearchParams] = useSearchParams();
  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 onClick={handleClick} type="button">
        자세히
      </button>
      {detail === "true" ? <p>{movie.detail}</p> : " "}
    </div>
  );
};

export default Movie;

8. 리액트 라우터 부가기능 사용하기

8.1 NotFound 페이지

Route로 지정해 주지 않은 경로로 들어갔을 때 찾을 수 없는 페이지 임을 사용자에게 알려주는 처리가 필요합니다.

App.js를 다음과 같이 수정해볼께요
📄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";
import Movie from "./pages/Movie";

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

export default App;

http://localhost:3000/Board
이렇게 입력해보세요! 존재하지 않은 페이지라고 잘 뜨나요?

8.2 Navigate 컴포넌트

페이지를 이동할 때는 Link 컴포넌트 이외에 또 다른 방법이 있습니다.
바로 Navigate 컴포넌트를 사용하는 방식입니다.

하단에 홈으로 돌아가는 버튼을 만들어볼께요

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

const Menubar = () => {
  //Navigate 사용하기
  const navigate = useNavigate();
  const goHome = () => {
    navigate("/");
  };
  return (
    <div>
      <ul>
        <li>
          <Link to="/">Home</Link>
        </li>
        <li>
          <Link to="/movies">Movies</Link>
        </li>
      </ul>

      <Outlet />

      <button onClick={goHome}>홈으로 돌아가기</button>
    </div>
  );
};

export default Menubar;

Link 대신 NavLink 컴포넌트를 사용하면 링크에서 사용하는 경로가 현재 라우트의 경로와 일치하는 경우 특정 CSS를 적용할 수 있습니다.

영화 목록 리스트 중 선택되어져 있는 리스트에 스타일을 적용해보도록 할께요.

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

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 ? "#FF9E1B" : "",
              };
            }}
          >
            <p>{movie.title}</p>
          </NavLink>
        ))}
      </div>
      <hr />
      <Outlet />
    </div>
  );
};

export default Movies;

선택된 영화 제목만 주황색으로 바뀌는 것을 확인하였나요?

여기까지 React Router를 활용한 프로젝트 만들기 따라오시느라 고생많으셨습니다!

CSS가 적용된 버전은 아래 github를 참고해주세요!
https://github.com/Chanran33/practice_router


참고자료
React Router v6 튜토리얼 : https://velog.io/@velopert/react-router-v6-tutorial#42-%EC%BF%BC%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%A7%81
React Router Tutorial : https://reactrouter.com/docs/en/v6/getting-started/tutorial#tutorial

profile
웹 개발자를 향하여

0개의 댓글