React - 리액트라우터

gombibi·2023년 3월 19일
0

React

목록 보기
4/5

1. 라우팅이란? 사용자가 요청한 URL에 따라 알맞은 페이지를 보여주는 것

  • 리액트 라우트 시스템은 대표적으로 리액트 라우터, Next.js 두가지가 있음
    - 리액트 라우터 : 가장 오래됐고, 많이 사용되고 있음. 라우팅 기능에만 집중
    - Next.js : 프로젝트 설정, 라우팅 시스템, 최적화, 다국어 시스템 지원, 서버 사이드 렌더링 등 다양한 기능 제공.

2. 싱글 페이지 애플리케이션
-멀티 페이지 애플리케이션 : 사용자가 다른 페이지로 이동할 때마다 새로운 html을 받아오고 서버에서 리소스 전달받아 브라우저 화면에 보여줌.

-싱글 페이지 애플리케이션 : html은 한번만 받아와서 웹 애플리케이션을 실행시킨 후, 사용자와의 인터랙션이 발생하면 필요한 부분만 js사용하여 화면에 업데이트.

3. 리액트 라우터 적용
1) 라이브러리 설치

//프로젝트 생성 후, 해당 폴더로 이동하여,
npm add react-router-dom

2) 프로젝트에 라우터 적용

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

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  //react-router-dom에 내장되어 있는 BrowserRouter 컴포넌트 사용
  //웹 애플리케이션에 HTML5의 History API를 사용하여 페이지를 새로 불러오지 않고도 주소를 변경하고 
  //현재 주소의 경로에 관련된 정보를 리액트 컴포넌트에서 사용할 수 있도록 해줌.
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

3) 페이지 컴포넌트 만들기

4) Route 컴포넌트로 특정 경로를 원하는 컴포넌트 보여주기

  • Route 컴포넌트는 다음과 같이 사용
  • Routes 컴포넌트 내부에서 사용되어야 함.
//사용방법
<Route path="주소규칙" element={보여줄 컴포넌트 JSX} />

//예시
//App.js
import { Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
    </Routes>
  );
}

export default App;

5) Link 컴포넌트 사용하여 다른 페이지로 이동하는 링크 보여주기

  • 리액트 라우터를 사용할 때, a태그를 바로 사용하면 안됨. 왜냐하면, a태그를 클릭하여 페이지를 이동할 때 브라우저에서는 페이지를 새로 불러오기 때문.
  • Link 컴포넌트 역시 a 태그를 사용하긴 하지만, 페이지 새로 불러오는 것을 막고, History API를 통해 브라우저 주소의 경로만 바꾸는 기능 내장.
//사용방법
<Link to="경로">링크 이름</Link>

//예시
//Home.js
import React from "react";
import { Link } from "react-router-dom";

const Home = () => {
  return (
    <div>
      <h1></h1>
      <p>가장 먼저 보여지는 페이지입니다.</p>
      //Home 페이지 -> About 페이지로 이동
      <Link to="/about">소개</Link>
    </div>
  );
};

export default Home;

4. URL 파라미터와 쿼리스트링
1) URL 파라미터: 주소의 경로에 유동적인 값을 넣는 형태
ex) /profile/bibi

//Profile.js
import React from "react";
import { useParams } from "react-router-dom";

const data = {
  bibi: {
    name: "bibi",
    description: "열공중",
  },
  cc: {
    name: "cc",
    description: "게임중",
  },
};
const Profile = () => {
  //URL 파라미터는 useParams라는 Hook을 이용하여 객체 형태로 조회할 수 있음.
  const params = useParams();
  const profile = data[params.username];

  return (
    <div>
      <h1>사용자 프로필</h1>
      {profile ? (
        <div>
          <h2>{profile.name}</h2>
          <p>{profile.description}</p>
        </div>
      ) : (
        <p>존재하지 않는 프로필입니다</p>
      )}
    </div>
  );
};

export default Profile;
//App.js
//URL 파라미터의 이름은 Route 컴포넌트의 path props를 통해 설정
//경로에 :를 사용하여 설정함.
import { Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Profile from "./pages/Profile";

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
      <Route path="/profile/:username" element={<Profile />} />
    </Routes>
  );
}

export default App;
//Home.js
import React from "react";
import { Link } from "react-router-dom";

const Home = () => {
  return (
    <div>
      <h1></h1>
      <p>가장 먼저 보여지는 페이지입니다.</p>
      <ul>
        <li>
          <Link to="/about">소개</Link>
        </li>
        <li>
          <Link to="/profile/bibi">bibi의 프로필</Link>
        </li>
        <li>
          <Link to="/profile/cc">cc 프로필</Link>
        </li>
        <li>
          <Link to="/profile/unkwown">존재하지않는 프로필</Link>
        </li>
      </ul>
    </div>
  );
};

export default Home;

2) 쿼리스트링: 주소의 뒷부분에 ? 문자열 이후에 key=value 값을 정의하며 $로 구분하는 형태
ex) articles?page=1&keyword=react

  • URL파라미터와 달리 Route 컴포넌트를 사용할 때 별도로 설정해야 하는 것이 없음.
  • useLocation 사용
//About.js
import React from "react";
import { useLocation } from "react-router-dom";

const About = () => {
  //useLocation Hook 사용 -> location 객체 반환
  //pathname: 현재 주소의 경로(쿼리스트링 제외)
  //search: ?를 포함한 쿼리스트링값
  //hash, state, key 값을 가지고 있음.
  const location = useLocation();

  return (
    <div>
      <h1>소개</h1>
      <p>리액트 라우터를 사용해 보는 프로젝트입니다.</p>
      <p>쿼리스트링: {location.search}</p>
    </div>
  );
};

export default About;
  • useSearchParams 사용
import React from "react";
import { useSearchParams } from "react-router-dom";

const About = () => {
  //위의 경우에는 ?도 지워야 하고, key와 value를 파싱하는 작업 필요
  //useSearchParams라는 Hook을 통해 쿼리스트링을 쉽게 파싱할 수 있음.
  //useSearchParams는 배열 타입의 값을 반환.
  //첫번째 원소는 쿼리파라미터를 조회하거나 수정하는 메서드들이 담긴 객체를 반환.
  //get 메서드로 특정 쿼리파라미터를 조회하고, set 메서드를 통해 업데이트 가능
  //두번째 원소는 쿼리파라미터를 객체 형태로 업데이트할수 있는 함수를 반환
  const [searchParams, setSearchParams] = useSearchParams();
  const detail = searchParams.get("detail");
  const mode = searchParams.get("mode");

  //쿼리파라미터 조회할 때 값은 무조건 문자열 타입이므로, boolean은 따옴표로 감싸고, 숫자는 parseInt를 사용하여 비교
  const onToggleDetail = () => {
    setSearchParams({ mode, detail: detail === "true" ? false : true });
  };

  const onIncreaseMode = () => {
    const nextMode = mode === null ? 1 : parseInt(mode) + 1;
    setSearchParams({ mode: nextMode, detail });
  };

  return (
    <div>
      <h1>소개</h1>
      <p>리액트 라우터를 사용해 보는 프로젝트입니다.</p>
      <p>detail: {detail}</p>
      <p>mode: {mode}</p>
      <button onClick={onToggleDetail}>Toggle detail</button>
      <button onClick={onIncreaseMode}>mode + 1</button>
    </div>
  );
};

export default About;

5. 중첩된 라우트

//App.js
import { Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Profile from "./pages/Profile";
import Articles from "./pages/Articles";
import Article from "./pages/Article";

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
      {/* URL 파라미터의 이름은 Route 컴포넌트의 path props를 통해 설정 */}
      <Route path="/profile/:username" element={<Profile />} />
      {/* 중첩된 라우터 사용하기
      <Route path="/articles" element={<Articles />} />
      <Route path="/articles/:id" element={<Article />} /> */}
      <Route path="/articles" element={<Articles />}>
        <Route path=":id" element={<Article />} />
      </Route>
    </Routes>
  );
}

export default App;
//Articles.js
import React from "react";
import { Link, Outlet } from "react-router-dom";

const Articles = () => {
  return (
    <div>
      {/* Outlet 컴포넌트 사용 -> Route의 children으로 들어가는 JSX 엘리먼트를 보여주는 역할 */}
      <Outlet />
      <ul>
        <li>
          <Link to="/articles/1">게시글 1</Link>
        </li>
        <li>
          <Link to="/articles/2">게시글 2</Link>
        </li>
        <li>
          <Link to="/articles/3">게시글 3</Link>
        </li>
      </ul>
    </div>
  );
};

export default Articles;
  • 중첩된 라우터와 Outlet은 페이지끼리 공통적으로 보여줘야하는 레이아웃이 있을 때 유용하게 사용할 수도 있음 ex) header
//Layout.js
import React from "react";
import { Outlet } from "react-router-dom";

const Layout = () => {
  return (
    <div>
      <header style={{ background: "lightgray", padding: 16, fontSize: 24 }}>
        Header
      </header>
      <main>
        <Outlet />
      </main>
    </div>
  );
};

export default Layout;
//App.js
import { Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Profile from "./pages/Profile";
import Articles from "./pages/Articles";
import Article from "./pages/Article";
import Layout from "./Layout";

function App() {
  return (
    <Routes>
      <Route element={<Layout />}>
        {/* index props는 path="/"와 동일한 의미. 좀 더 명시적으로 표현할 수 있음 
        <Route path="/" element={<Home />} /> */}
        <Route index element={<Home />} />
        <Route path="/about" element={<About />} />
        {/* URL 파라미터의 이름은 Route 컴포넌트의 path props를 통해 설정 */}
        <Route path="/profile/:username" element={<Profile />} />
      </Route>
      {/* 중첩된 라우터 사용하기
      <Route path="/articles" element={<Articles />} />
      <Route path="/articles/:id" element={<Article />} /> */}
      <Route path="/articles" element={<Articles />}>
        <Route path=":id" element={<Article />} />
      </Route>
    </Routes>
  );
}

export default App;

6. 부가기능
1) useNavigate : Link 컴포넌트를 사용하지 않고 다른 페이지로 이동해야 하는 상황에 사용하는 Hook

const navigate = useNavigate();
//파라미터가 숫자타입이라면
//이전 페이지로 이동
navigate(-1);
//뒤로 두번 이동
navigate(-2);
//다시 앞으로 이동(뒤로가기 상태에서)
navigate(1);

//파라미터가 문자열이라면, 해당 경로로 이동
navigate('/articles');

//replace 옵션을 사용하면, 페이지를 이동할 때 현재 페이지를 페이지 기록에 남기지 않음
navigate('/articles', {replace:true});

2) NavLink : 링크에서 사용하는 경로가 현재 라우트의 경로와 일치하는 경우 특정 스타일 또는 CSS 클래스를 적용하는 컴포넌트
-style, className은 {isActive:boolean}을 파라미터로 전달받는 함수 타입의 값을 전달

<NavLink style={({isActive}) => isActive ? activeStyle : undefined}/>

<NavLink style={({isActive}) => isActive ? 'active' : undefined}/>

3) NotFound 페이지 만들기
-path가 일치하는 라우트가 없으면 이 라우트가 화면에 나타나게 됨

//App.js
<Route path="*" element={<NotFound />}></Route>

4) Navigate 컴포넌트 : 컴포넌트를 화면에 보여주는 순간 다른 페이지로 이동을 하고 싶을 때 사용하는 컴포넌트. (리다이렉트)
ex) 사용자의 로그인이 필요한 페이지인데 로그인을 안했드면 로그인 페이지를 보여줘야 함

if(!isLoggedIn){
	return <Navigate to="/login" replace={true}/>;	
}

! 라우트에 따라 필요한 컴포넌트만 불러오고, 다른 컴포넌트는 다른 페이지로 이동하는 등 필요한 시점에 불러오도록 하는 건 '코드 스플리팅'으로 해결 가능

참고: 리액트다루는기술(김민준)

profile
말랑말랑한 개발자가 되자:D

0개의 댓글