React Router v6 요약

Jake·2022년 7월 9일
0

React Router DOM

목록 보기
1/1
post-thumbnail

[요약]
HTML5의 History API를 활용한 라우팅으로 SPA 개발을 도와주는 react 확장 라이브러리

Reference

1.라우팅(Routing)?

: 사용자가 요청한 URL에 따라 알맞는 페이지를 보여주는 것

1.1 React에서 라우트 시스템 구축을 위한 두 가지 선택지

    1. React-Router-Dom
      = SPA 개발
    1. Next.js
      = React + express.js + 파일경로 기반 라우팅 + SEO(검색엔진최적화) + SSR(서버사이드렌더링)

1.2 프로젝트에 라우터 적용

npm install react-router-dom

src>index.js

import React from 'react';
import { BrowserRouter } from 'react-router-dom';

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

src/index.js 파일에서 react-router-dom에 내장되어 있는 BrowserRouter라는 컴포넌트를 사용하여 감싸준다.
//router-dom을 적용할 컴포넌트의 최상위 컴포넌트에 래핑해주면 하위 컴포넌트 모두에 적용가능하다.

*BrowserRouter컴포넌트 기능: HTML5의 History API를 사용하여 페이지를 새로 불러오지 않고도
주소를 변경하고, 현재 주소 경로에 관련된 정보를 리액트 컴포넌트에서 사용할 수 있도록 해줌.


2.내장기능

2.1 Route

특정 경로에서 원하는 컴포넌트를 보여주기
<Route path="/주소규칙" element={보여줄컴포넌트JSX}/>

  • <Route>컴포넌트는 반드시 <Routes>컴포넌트로 감싸주어야한다.
<Routes>
      <Route path="/" element={<Layout/>}>
        <Route path="/" element={<Home/>}> </Route>
        <Route path="/About" element={<About/>}> </Route>
        <Route path="/profiles/:username" element={<Profile/>}> </Route>
      </Route>
      <Route path="/articles" element={<Articles/>}>
        <Route path=":id" element={<Article/>}/>
      </Route>
      {/* :가 붙은 주소변수는 입력받는 유동값을 의미한다. */}
      <Route path="/login" element={<Login/>} />
      <Route path="*" element={<NotFound />} />
      {/* *는 wildcard문자 , 아무 텍스트나 매칭, 위 모든 path규칙을 확인하고 일치하는 값이 
      없다면 이 라우트가 화면에 나타난다. */}
</Routes>

컴포넌트 클릭시 to속성으로 설정한 경로로 라우팅시켜준다.
<a href="경로"></a>
: 클릭시 페이지를 새로 불러옴.
<Link to="경로"> 링크이름 </Link>
: 클릭시 페이지를 새로 불러오지 않음.

2.3 URL parameter & 쿼리스트링

URL parameter

URL 파라미터는 주소의 경로에 :username과 같이 유동적인 값을 넣는 형태이고,
<Route path="/profiles/:username" element={<Profile/>}> </Route>

  • URL 파라미터 예시: /profiles/jakeshim

src/pages/Profile.js

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

const data = {
  jakeshim: {
      name: '심현준',
      description: 'FE developer',
  },
  gildong: {
    name: '홍길동',
    description: '고전 소설 홍길동전의 주인공',
  },
};
//data객체 생성 

const Profile = () => {
  const params = useParams(); //useParams() hook 사용
  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;

src/App.js

<Route path="/profiles/:username" element={<Profile/>}> </Route>

라우트 경로에 설정한 :username(설정값)에 의해
const params =useParams();값은

  • { username: 'jakeshim' }
  • { username: 'gildong' } 의 값을 각각 반환한다.
    주소창 입력시마다 {설정한 값: 입력한값}의 객체를 유동적으로 반환

쿼리 스트링은 주소의 뒷부분에 ? 문자열 이후에 key=value 로 값을 정의하며 & 로 구분을 하는 형태.

  • 쿼리스트링 예시: /articles?**page=1&keyword=react
    // ?key=value&key=value

쿼리스트링

쿼리스트링을 사용할 때는 URL파라미터와 달리 Route컴포넌트를 사용할 때 별도로 설정해야되는 것은 없다.

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

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

# location 객체란?

useLocation()훅의 반환값으로써, 사용자가 보고있는 페이지의 정보를 지닌 객체이다.

  • const location = useLocation(); //location객체 반환
  • pathname: 현재 주소의 경로 (쿼리스트링 제외)
  • search: 맨 앞의 ? 문자 포함한 쿼리스트링 값
  • hash: 주소의 # 문자열 뒤의 값 (주로 History API 가 지원되지 않는 구형 브라우저에서 클라이언트 라우팅을 사용할 때 쓰는 해시 라우터에서 사용합니다.)
  • state: 페이지로 이동할때 임의로 넣을 수 있는 상태 값
  • key: location 객체의 고유 값, 초기에는 default 이며 페이지가 변경될때마다 고유의 값이 생성됨

3.라우트 중첩

src/App.js

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

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

      <Route path="/login" element={<Login/>} />
      <Route path="*" element={<NotFound />} />
    </Routes>
);

export default App;

중첩된 라우트자식라우트들은 부모라우트의 요소컴포넌트 안에서
<Outlet/>컴포넌트로 보여줄 수 있다.

/경로에서는 LayoutLayout컴포넌트를 렌더링해서 보여주고 Layout`은 자식라우트의 엘리먼트컴포넌트에서 공통으로 보여진다.

즉, "안에있는걸 바깥(라우트의 컴포넌트)에서 보여준다" 라고 생각하면됨.

src/Layout.js

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

const Layout = () => {
return (
      <div>
      <header style={{ background: 'lightgray', padding: 16, fontSize: 24 }}>
      </header>
      <main>
      <Outlet />   
  /*Outlet에 속한 자식라우트로 각각 이동했을 때
  부모 라우트의 엘리먼트인 Layout컴포넌트는 
  각 라우트에서 여전히 지속된다.*/
      </main>
    </div>
  );
};

export default Layout;

## Another Example in

https://reactrouter.com/docs/en/v6/getting-started/tutorial [Nested Routes]

src/routes/expenses.jsx

export default function Expenses() {
    return (
      <main style={{ padding: "1rem 0" }}>
        <h2>Expenses</h2>
      </main>
    );
  }

src/routes/invoices.jsx

export default function Invoices() {
    return (
      <main style={{ padding: "1rem 0" }}>
        <h2>Invoices</h2>
      </main>
    );
  }

src/App.js

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

export default function App() {
  return (
    <div>
      <h1>Bookkeeper</h1>
      <nav
        style={{
          borderBottom: "solid 1px",
          paddingBottom: "1rem",
        }}
      >
        <Link to="/invoices">Invoices</Link> |{" "}
        <Link to="/expenses">Expenses</Link>
      </nav>
      <Outlet />
    </div>
  );
}

index.js

import ReactDOM from "react-dom/client";
import {
  BrowserRouter,
  Routes,
  Route,
} from "react-router-dom";
import App from "./App";
import Expenses from "./routes/expenses";
import Invoices from "./routes/invoices";

const root = ReactDOM.createRoot(
  document.getElementById("root")
);
root.render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />}>
        <Route path="expenses" element={<Expenses />} />
        <Route path="invoices" element={<Invoices />} />
      </Route>
    </Routes>
  </BrowserRouter>
);

The parent route (App.js) persists while the <Outlet>
swaps between the two child routes (<Invoices> and <Expenses>)!

<outlet/>은 자식라우트에서 보여주는 컴포넌트를 추상적으로 의미하고
각 자식 라우트의 경로로 이동했을 때, <App/>컴포넌트를 렌더링해서 보여주며 <outlet/>의 자리에는 각 자식라우트가 보여주는 컴포넌트가 위치하게 된다.


4. 리액트 라우터 부가기능

4.1 useNavigate : Hook

useNavigate() 반환값을 const navigate 식별자에 할당한다.

  • navigate(-1) 뒤로가기
  • navigate('/articles', {replace: true}) 특정경로로 이동하기
    //{replace: true}는 이동 시점의 주소 기록을 남기지 않는다.

다음과같이 이벤트핸들러로 등록해서 사용할 수 있다.

const goArticles = () => {
  navigate('/articles', { replace: true });
}
<button onClick={goArticles}> 게시글로  </button>

'/' -> Home -> About -> 게시글목록클릭('/articles'로 이동)
{relace:true}를 2nd parameter 로 주었기 때문에
이동시점의 페이지(About)페이지를 페이지 히스토리에 남기지
않아서 뒤로가기(navigate(-1))시 Home이 나타나게된다.

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

이 컴포넌트를 사용시 'style' 또는 'className'을 설정할 때
{ isActive: boolean } 을 파라미터로 전달받는 함수 타입의 값을 전달함.

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

NavLink컴포넌트 활성화시
const {isActive:isActive} = {isActive: true} 객체구조분해할당으로
isActive = true 로 style의 값으로 전달됨.

[추가]
#1.
<NavLink to="url" style={ ({isActive : isActive}) => isActive ? activeStyle :undefined }
//객체 프로퍼티축약
//NavLink 컴포넌트 클릭시 해당 isActive = true가 전달되면서 style={activeStyle}이 적용됨.
//react는 style={ css객체 } 로 전달받는다.

#2.<NavLink className={({isActive}) => isActive ? 'active' : undefined}

src/pages/Articles.js

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

const Articles = () => {
  const activeStyle = {
    color: 'green',
    fontSize: 21,
  };

  return (
    <div>
      <Outlet />
      <ul>
        <li>
          <NavLink
            to="/articles/1"
            style={({ isActive }) => (isActive ? activeStyle : undefined)}
          >
            게시글 1
          </NavLink>
        </li>
        <li>
          <NavLink
            to="/articles/2"
            style={({ isActive }) => (isActive ? activeStyle : undefined)}
          >
            게시글 2
          </NavLink>
        </li>
        <li>
          <NavLink
            to="/articles/3"
            style={({ isActive }) => (isActive ? activeStyle : undefined)}
          >
            게시글 3
          </NavLink>
        </li>
      </ul>
    </div>
  );
};

export default Articles;

4.3 NotFound 페이지만들기

<Route path="*" element={<NotFound/>} />
라우트를 라우트 맨 아랫단에 위치시켜
이 라우트 엘리먼트 상단에 위치하는 라우트들의 규칙을 모두 확인하고
일치하는 라우트가 없다면 이 라우트가 화면에 나타나게 된다.

'*'는 wildcard문자로써 이는 아무 텍스트나 매칭한다는 의미임.

import { Route, Routes } from 'react-router-dom';
import Layout from './Layout';
import About from './pages/About';
import Article from './pages/Article';
import Articles from './pages/Articles';
import Home from './pages/Home';
import NotFound from './pages/NotFound';
import Profile from './pages/Profile';

const App = () => {
  return (
    <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>
      <Route path="*" element={<NotFound />} />
    </Routes>
  );
};

export default App;

4.4 Navigate 컴포넌트

컴포넌트를 화면에 보여주는 '순간' 페이지를 리다이렉트하고 싶을 떄 사용한다.

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

const MyPage = ()=>{
 const inLoggedIn = false;
 
 if(!isLoggedIn) {
   return <Navigate to="/login" replace={true} />;
 }  /*return문은 그 즉시 값을 리턴하고, 해당 함수의 실행을멈춘다 (if문은 함수가 아니므로
   MyPage함수 실행을 즉시 중단하고, return문 이후의 코드를 무시한다.)
   return <div>마이페이지</div>;*/
};

export default MyPage;

isLoggedIn값이 false,즉 로그인이 안돼있으면 MyPage컴포넌트는
<Navigate to="/login" replace={true} />

profile
young하고 MZ해요

0개의 댓글