본문 바로가기
리액트(React)

리액트 라우터(React Router) 사용법(4)

by 즐거운코딩 2023. 5. 29.
반응형

1. 라우터에서 쿼리스트링을 사용하는 방법

우선 쿼리스트링을 화면에 표출해 봅니다.

import { useLocation } from 'react-router-dom';

const About = () => {
  const location = useLocation();

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

export default About;

useLocation 이라는 Hook을 사용합니다. 이 훅은 location이라는 객체를 반환하는데 사용자가 보고 있는 페이지 정보를 가지고 있습니다.

  • pathname : 현재 주소의 경로 (쿼리스트링 제외)
  • search : 맨 앞의 ? 문자를 포함한 쿼리스트링 값
  • hash : 주소의 # 문자열 뒤의 값 (해시 라우터에서 사용)
  • state : 페이지로 이동할 때 임의로 넣을 수 있는 상태 값
  • key : location 객체의 고유 값. 초기에는 default이며 페이지가 변경될 때마다 고유의 값이 생성

위의 속성중 location.search. 값을 통해 쿼리스트링 값을 가져올 수 있습니다.
쿼리스트링 값에서 ? 을 지우고, & 문자열로 분리한 뒤 key 와 value로 파싱하는 작업을 해야하는데 리액트 라우터에 useSearchParams 라는 Hook을 사용하면 됩니다.

import { useSearchParams } from 'react-router-dom';

const About = () => {
  const [searchParams, setSearchParams] = useSearchParams();
  const detail = searchParams.get('detail');
  const mode = searchParams.get('mode');

  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;

useSerachParams 는 배열 타입의 값을 반환하며, 첫 번째 원소는 쿼리파라미터를 조회하거나 수저하는 메서드들이 담긴 객체를 반환합니다. 두 번째 원소는 쿼리파라미터를 객체 형태로 업데이트 할 수 있는 함수를 반환합니다.

  • get 메서드 : 특정 쿼리파라미터를 조회
    만약 조회시 쿼리파라미터가 존재하지 않으면 null 로 조회
  • set 메서드 : 특정 쿼리파라미터를 업데이트

쿼리파라미터를 사용할 때 주의점

무조건 문자열 타입으로 true 또는 false 값을 비교할 때 꼭 'true' 와 같이 따옴표로 감싸서 비교해야하고,
숫자를 다룬다면 paseInt를 사용하여 숫자 타입으로 변환 해야 한다.

2. 중첩된 라우트

리액트 라우터에서 중첩된 라우트를 다루는 방법에 대해 알아봅니다.

우선 예시로 게시글 목록을 보여주는 페이지와 게시글 내용을 확인하는 페이지를 만들어 보겠습니다.

pages 디렉토리에 Articles.js 와 Article.js 페이지를 만듭니다.

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

const Articles = () => {
  return (
    <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>
  );
};

export default Articles;
import { useParams } from 'react-router-dom';

const Article = () => {
  const { id } = useParams();
  return (
    <div>
      <h2>게시글 {id}</h2>
    </div>
  );
};

export default Article;

App.js 에 Articles, Article 페이지를 넣어주고 라우트 설정을 합니다.

import Articles from './pages/Articles';
import Article from './pages/Article';
import './App.css';

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/profiles/:username" element={<Profile />} />
        <Route path="/articles" element={<Articles />} />
        <Route path="/articles/:id" element={<Article />} />
      </Routes>
    </BrowserRouter>
  );
};

export default App;

Articles.js

지금 작성한 형태의 게시글 상세 내용을 별도 페이지로 보여주는 것이 아니라 게시글 선택시 하단에 보여줘야 한다면 중첩된 라우트를 이용하여 좀 더 나은 방법으로 설정 가능합니다.

App.js 와 Articles.js 를 다음과 같이 수정합니다.

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/profiles/:username" element={<Profile />} />
        <Route path="/articles" element={<Articles />}>
          <Route path=":id" element={<Article />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
};

Articles 라우트 하위로  Article 라우트를 넣어 줍니다.

그리고 Articles 컴포넌트에 리액트 라우트에서 제공하는 Outlet 컴포넌트를 사용하면 Route의 children 으로 들어가는 JSX 엘리먼트를 보여주는 역할을 합니다. 이번 예제에서는 <Route path=":id" element={Article />} /> 가 보여집니다.

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

const Articles = () => {
  return (
    <div>
      <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>
  );
};

게시글 1, 2, 3 리스트 밖에 div tag 추가하고 <Outlet /> 컴포넌트를 넣어 줍니다.

게시글 상세 내용에 게시글 목록 표출

2-1 중첩된 라우트 활용 공통 레이아웃 컴포넌트 만들기

웹 페이지면 상단에 공통적으로 헤더를 보여줘야 한다면 Header 컴포넌트를 따로 만들어 두고 각 페이지 컴포넌트에서 재사용하는 방법을 일반적으로 생각합니다.

하지만 중첩된 라우터 Outlet을 활용하여 구현할 수 있습니다.

예시로 공통 레이아웃을 위한 Layout 컴포넌트를 src 디렉토리에 만듭니다.

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 도 아래와 같이 바꿔 줍니다.  Layout 컴포넌트 하위로 페이지들을 넣어줍니다.

Home, About, Profile 페이지만 Header 공통으로 표시합니다.

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route element={<Layout />}>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/profiles/:username" element={<Profile />} />
        </Route>
        <Route path="/articles" element={<Articles />}>
          <Route path=":id" element={<Article />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
};

2-2 index props 사용해보기

Route 컴포넌트에는 index라는 props 가 있는데 path="/" 와 동일한 의미를 가집니다.

이것을 활용하여 Home 컴포넌트가 사용된 Route 컴포넌트를 다음과 같이 변경해봅니다.

App.js 의 Route 수정

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Layout />}>
          <Route index element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/profiles/:username" element={<Profile />} />
        </Route>
        <Route path="/articles" element={<Articles />}>
          <Route path=":id" element={<Article />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
};

index prop을 사용하면 상위 라우트의 경로와 일치하지만, 그 이후에 경로가 주어지지 않을 때 보여지는 라우트를 설정할 수 있습니다.

반응형