React Router

seul_velog·2022년 4월 14일
0

React

목록 보기
9/11
post-thumbnail

SPA

SPA(Single Page Application)
: 페이지가 하나인 어플리케이션
하나의 url로 한 번 페이지가 로딩된 후, 사용자가 다른 페이지로 넘어갈 때(링크 클릭 등) 새로운 페이지가 열리지 않고, 부분내용만 업데이트 되는 싱글페이지 어플리케이션이다.

📌 리액트는 SPA 어플리케이션을 쉽게 만들 수 있도록 도와주는 라이브러리 이다.

  • 전통적인 웹어플리케이션(멀티 페이지 애플리케이션) 구조는 여러 페이지로 구성되어 있었다.
    유저 요청시 매번 페이지가 새로고침되고 서버로부터 리소스를 전달받아 해석 후 렌더링을 했으며, 뷰가 어떻게 보여질지도 서버에서 담당했다.

    → 하지만 사용자와 인터랙션이 많은 모던 웹어플리케이션에서는 렌더링하는 것을 서버쪽에서 담당하기에는 서버 자원과 트래픽(서버의 데이터 전송량)이 낭비된다.

    → 따라서 리액트와 같은 라이브러리나 프레임워크를 사용해서 뷰 렌더링을 유저의 브라우저가 담당하도록 하고 우선 어플리케이션을 브라우저에 실행한 다음, 사용자와의 인터랙션이 발생하면 필요한 데이터만 전달받아 보여줄 수 있게 한다.

    → 이렇게 html은 한번만 받아와서 웹 애플리케이션을 실행시킨 후에 그 이후에는 필요한 데이터만 받아와서 화면에 업데이트 해주는 것이 SPA이다.


📌 SPA 의 단점

  • 북마크 하기 어렵다.
  • 페이지 안에서만 동작이 일어나므로 브라우저상에서 뒤로가기, 앞으로가기 등이 내비게이션에 추가되지 않는다.





리액트 라우터

Routing 이란?

사용자가 요청한 url에 따라 어떤 특정한 페이지로 연결한다.

  • 즉, 다른 주소에 따라 다른 뷰를 보여주는 것을 라우팅 이라고 한다.
  • 하나의 블로그를 만든다고 가정했을 때, 각각의 싱글 페이지(ex. 블로그 : 홈, 포스트목록, 포스트, 글쓰기 등)가 필요할 수 있다. 이처럼 여러 페이지로 구성된 웹 앱플리케이션을 만들 때 페이지별로 컴포넌트를 분리해가면서 프로젝트를 관리하기 위해 필요한 것이 라우팅 시스템이다.
  • 📌 SPA 라우팅 과정

    1) 브라우저에서 최초에 '/' 경로로 요청을 한다.
    2) 서버는 React Web App 을 내려준다.
    3) 내려받은 React App 에서 / 경로에 맞는 컴포넌트를 보여준다.
    4) React App 에서 다른 페이지로 이동하는 동작을 수행하면
    5) 새로운 경로에 맞는 컴포넌트를 보여준다.

  • ❗️ 리액트는 컴포넌트를 작성, 효율적으로 렌더링하는 것에 치중된 프로그램이다. 라우팅 기능은 내장되어 있지 않다.



React Router

클라이언트 사이드에서 이루어지는 라우팅을 간단하게 해주며, 가장 대표적인 라우팅 패키지이다.
여러 화면으로 구성된 웹 어플리케이션을 만들게 된다면, react-router 는 필수 라이브러리이다.

  • cra에 기본 내장된 패키지가 아니다.
  • 공식 패키지는 아니지만 가장 많이 사용되고 있는 써드파티 라이브러리이다.
  • react-native에서도 사용된다.
  • 서버 사이드 렌더링을 도와주는 도구들도 함께 따라온다.
  • 컴포넌트 기반으로 라우팅 시스템을 설정할 수 있다.
  • 손쉽게 싱글 페이지 애플리케이션 (Single Page Application)을 만들 수 있다.
    SPA 단점 보완!
    싱글페이지 어플리케이션을 유지하면서 url을 붙일 수 있도록 한다. 해당하는 페이지로 바로 이동하고 북마크 및 뒤로가기, 앞으로가기 네비게이션에도 추가할 수 있도록 도와준다.

✍️ 최근에 버전 5 → 버전 6 으로 큰 버전 업데이트가 되었다고 한다. 새로운 버전으로 차근차근 알아가자.😀







React Router v6 사용해보기

BrowserRouter

프로젝트에 리액트 라우터를 적용해보자.

$ npm i react-router-dom
$ yarn add react-router-dom

ex.)

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

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



Route

Route 컴포넌트를 통해 라우트 설정하기

Route 사용방식

<Route path="주소규칙" element={보여 줄 컴포넌트 JSX}></Route>
  • Route 컴포넌트는 Routes 컴포넌트 내부에서 사용되어야 한다.
  • Route 들은 내가 보여줄 각각의 페이지들 이라고 이해하자.

ex.)

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



Link 컴포넌트를 통해 다른 주소로 이동시키기

  • 리액트 라우터를 사용할 땐 일반 <a href="...">...</a> 태그를 사용하면 안된다.
    (한다면 onClicke.preventDefault() 를 호출하고 따로 자바스크립트로 주소를 변환시켜 주는 작업이 필요하다고..)

Link 컴포넌트

  • <a> 태그를 사용하지 않는 이유는 무엇일까 🤔
    : <a> 태그의 기본 속성은 페이지를 이동하면서 새로 불러온다는 것이다. 그렇게 되면 리액트 앱이 지닌 상태들도 초기화되고 렌더링된 컴포넌트도 모두 새로 렌더링을 하게 되기 때문!
    → 따라서 Link 컴포넌트를 사용한다.

  • Link 컴포넌트 역시 a 태그를 사용하긴 하지만, 페이지를 새로 불러오는 것을 막고 HTML5 History API 를 통해 브라우저 주소의 경로만 바꾸는 기능이 내장되어 있다.

ex.)

import React from 'react';
import {Link} from 'react-router-dom'
const Home = () => {
  return (
    <div>
      <h1></h1>
      <p>가장 먼저 보여지는 페이지입니다.🏠</p>
      <Link to='/about'>소개</Link>
    </div>
  );
};

export default Home;



동적 라우팅

파라미터와 쿼리스트링

URL Params & Query String
페이지 주소를 정의 할 때, 유동적인 값을 전달하기

1. URL Params

  • ex.) /profile/seul
  • 주소의 경로에 유동적인 값을 넣는 형태이다.
  • 주로 ID 또는 이름을 사용하여 특정 데이터를 조회할 때 사용한다.
  • useParams Hook 을 사용하여 객체 형태로 조회할 수 있다.

  • URL 파라미터의 이름은 라우트 설정을 할 때 Route 컴포넌트의 path props를 통하여 설정한다.

       <Route path='/profile/:username' element={<Profile />} 
  • URL 파라미터는 /profiles/:username 과 같이 경로에 : 를 사용하여 설정한다. 만약 URL 파라미터가 여러개인 경우엔 /profiles/:username/:field 와 같은 형태로 설정할 수 있다.

    ex.)

    import React from 'react';
    import { useParams } from 'react-router-dom';
    
    // 프로필에서 사용할 데이터
    const data = {
      kim: {
        name: 'seul',
        description: '코딩은 정말 재밌어 ✨!',
      },
      lee: {
        name: 'nasa',
        description: '천문학을 배우면 겸손해져. 🔭',
      },
    };
    
    const Profile = () => {
      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;
    

2. Query

  • Query String
  • ex.) /articles?**page=1&keyword=react
  • 주소의 뒷부분에 ? 문자열 이후에 key=value 로 값을 정의하며 & 로 구분을 하는 형태이다.
  • 키워드 검색, 페이지네이션, 정렬 방식 등 데이터 조회에 필요한 옵션을 전달할 때 사용한다.

2-1) useLocation Hook

  • location 객체를 반환하며 이 객체는 현재 사용자가 보고있는 페이지의 정보를 지니고 있다.

  • 쿼리스트링은 location.search 값을 통해 조회를 할 수 있다.

    ex.)

    import { useLocation } from 'react-router-dom';
    
    const About = () => {
      const location = useLocation();
      console.log(location.search);
      return (
        <div>
          <h1>소개&</h1>
          <p>리액트 라우터를 사용해 보는 프로젝트입니다.</p>
          <p>쿼리스트링: {location.search}</p>
        </div>
      );
    };

2-2) useSearchParams Hook

  • React Router v6부터 useSearchParams 라는 Hook을 통해서 쿼리스트링을 더욱 쉽게 다룰 수 있게 되었다. (쿼리스트링 값을 쉽게 파싱해줌😀 )

  • 배열 타입의 값을 반환한다.
    - 첫 번째 원소 : 쿼리파라미터를 조회하거나 수정하는 메서드들이 담긴 객체를 반환.
    getset 메서드를 통해 특정 쿼리파라미터를 조회하거나 업데이트할 수 있다. 조회시 쿼리파라미터가 존재하지 않는다면 null 로 조회된다.
    - 두 번째 원소 : 쿼리파라미터를 객체형태로 업데이트할 수 있는 함수를 반환.

  • 쿼리파라미터를 조회할 때 값은 무조건 문자열 타입이다.

    ex.)

    import React from 'react';
    import { useSearchParams } from 'react-router-dom';
    
    const About = () => {
      const [searchParams, setSearchParams] = useSearchParams();
      const detail = searchParams.get('detail');
      const mode = searchParams.get('mode');
    
      const onToggleDetail = () => {
        // true는 문자열 '' 로 감싸서 값을 비교하기
        // mode를 넣지 않으면 onToggleDetail콜백 실행시 mode값이 null로 초기화
        setSearchParams({ detail: detail === 'true' ? false : true, mode });
      };
    
      const onIncreaseMode = () => {
         // 숫자는 parseInt로 숫자 타입으로 변환하기
         // detail 넣지 않으면 onIncreaseMode콜백 실행시 detail값이 null로 초기화
        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;
    



중첩된 라우트

라우트 내부의 라우트 만들기
컴포넌트를 만들어서 그 안에 또 Route 컴포넌트를 렌더링한다.

Outlet 컴포넌트

  • 리액트 라우터에서 제공하는 Outlet 컴포넌트는 Routechildren 으로 들어가는 JSX 엘리먼트를 보여주는 역할을 한다.

  • 중첩된 라우트와 Outlet페이지끼리 공통적으로 보여지는 레이아웃을 유용하게 사용할 수도 있다. (ex.header 컴포넌트 등) 이때, 중첩된 라우트 방식을 사용하면 컴포넌트를 한 번만 사용해도 된다는 장점이 있다.

ex.)

// App.js
const App = () => {
  return (
    <Routes>
      
    <Route element={<Layout />}>
        <Route index element={<Home />} />
        <Route path='/about' element={<About />} />
        <Route path='/profile/:username' element={<Profile />} />
      </Route>

      <Route path='/articles/' element={<Articles />}>
        <Route path=':id' element={<Article />} />
      </Route>

    </Routes>
  );
};
// articles.jsx
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>
  );
};

export default Articles;

// article.jsx
import { useParams } from 'react-router-dom';

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

export default Article;
// layout.jsx
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;



index props

Route 컴포넌트 안의 index props

  • path='/' 와 동일한 역할을 하며 더 명시적으로 표현하는 방법이다.
  • index props은 상위 라우트의 경로와 일치한다.

ex.)

<Route index element={<Home />} />





리액트 라우터 부가기능

라우팅에 관련된 작업을 할 때 유용하게 사용되는 API들

useNavigate()

Link 가 특정 주소로 이동해주는 태그라면, Navigate 는 특정 행동을 했을 때 해당 주소로 이동해준다.

navigate("../success",  { replace: true });
  • 첫 번째 인자 : 주소
  • 두 번째 인자 : {replace, state} 인수 → replace(ture or false)
  • Link 컴포넌트를 사용하지 않고 다른 페이지로 이동을 해야 하는 상황에 사용한다.
  • navigate 함수를 사용할 때 파라미터가 숫자 타입이라면 앞으로 가거나, 뒤로 간다.
  • 페이지 이동시 replace 옵션을 사용하면 현재 페이지를 기록에 남기지 않는다. (뒤로가기 시 건너 뜀)
  • useNavigate() 는 react v6에서 useHistory가 변화한 것이다. 이 때 useHistory 에서 사용하던 window의 history 를 이용한 navigate 기능도 할 수 있다고 한다.
  • 📌 History
    : 세션 기록(페이지 방문 기록)에 대한 접근 방법과 메서드를 제공하는 것이다.
    (세션은 웹 사이트의 여러 페이지에 걸쳐 사용되는 사용자 정보를 저장하는 방법이다.)

ex.)

const Layout = () => {
  const navigate = useNavigate();

  const goBack = () => {
    // 이전 페이지로 이동
    navigate(-1);
  };

  const goArticles = () => {
    // 현재 페이지를 페이지 기록에 남기지 않음
    navigate('/articles', { replace: true });
  };

  return (
    <div>
      <header style={{ background: 'lightgray', padding: 16, fontSize: 24 }}>
        <button onClick={goBack}> 뒤로가기 </button>
        <button onClick={goArticles}> 게시글 목록 </button>
      </header>
      <main>
        <Outlet />
      </main>
    </div>
  );
};



링크에서 사용하는 경로가 현재 라우트의 경로와 일치하는 경우 특정 스타일 또는 CSS 클래스를 적용한다.

  • activeClassName, activeStyle 처럼 active 상태에 대한 스타일 지정이 가능하다.
  • 이 컴포넌트 사용시 style 또는 className 을 설정할 때 { isActive: boolean } 을 파라미터로 전달받는 함수 타입의 값을 전달한다.

ex.)

 const activeStyle = {
    color: 'pink',
    fontSize: 20,
  };
  
<li>
  <NavLink 
  to='/articles/1'
  style={({ isActive }) => (isActive ? activeStyle : undefined)}
    >
    게시글1
</NavLink>
</li>



NotFound

페이지를 찾을 수 없을 때 나타나는 페이지

  • 사전에 정의되지 않은 경로에 사용자가 진입했을 때 보여주는 페이지이다.
<Route path='*' element={<NotFound />} />
  • * 는 wildcard 문자로, 아무 텍스트나 매칭한다는 뜻이다. 즉, 이 라우트는 엘리먼트 상단에 위치하는 라우트들의 규칙을 모두 확인하고, 일치하는 라우트가 없다면 이 라우트<NotFound /> 를 화면에 보여준다.



페이지를 리다이렉트 할 때 사용한다.

  • 컴포넌트를 화면에 보여주는 순간 다른 페이지로 이동을 하고 싶을 때 사용한다.
    ✍️ 리다이렉트❓
    → 쉽게 말하자면 컴퓨터 바탕 화면의 여러 바로가기와 같은 개념이다.
  • ex.) 로그인이 필요한 페이지에서 비로그인 상태로 접근을 할 경우 로그인 페이지를 띄운다.







reference)
vlpt-react-router
dreamcoding
fastcampus
useNavigate

profile
기억보단 기록을 ✨

0개의 댓글