ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • react-router-dom
    리액트 2021. 9. 15. 19:12

    리액트는 안타깝게도 라우팅 기능을 내장 되어있지 않아 이를 도와줄 수 있는 라이브러리를 사용해야 합니다. 많고많은 리액트 라우터 라이브러리 중에 사람들이 가장 많이 사용하는 react-router-dom에 대하여 알아보겠습니다.  

    설치

    먼저 새로운 프로젝트 생성 후  해당 프로젝트 디렉토리로 이동하겠습니다.

    npx create-react-app router-practice
    cd router-practice

     

    그 후 react-router-dom 라이브러리를 설치하겠습니다.

    npm install react-router-dom

    예시 1 :  기본 라우팅

    import React from "react";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link
    } from "react-router-dom";
    
    export default function App() {
      return (
        <Router>
          <div>
            <nav>
              <ul>
                <li>
                  <Link to="/">Home</Link>
                </li>
                <li>
                  <Link to="/about">About</Link>
                </li>
                <li>
                  <Link to="/users">Users</Link>
                </li>
              </ul>
            </nav>
    
            {/* A <Switch> looks through its children <Route>s and
                renders the first one that matches the current URL. */}
            <Switch>
              <Route path="/about">
                <About />
              </Route>
              <Route path="/users">
                <Users />
              </Route>
              <Route path="/">
                <Home />
              </Route>
            </Switch>
          </div>
        </Router>
      );
    }
    
    function Home() {
      return <h2>Home</h2>;
    }
    
    function About() {
      return <h2>About</h2>;
    }
    
    function Users() {
      return <h2>Users</h2>;
    }

     

    위의 예시를 보시면 라우터가 3개의 페이지(home 페이지, about 페이지, users 페이지)를 처리하고 있습니다. 세개의 다른 <Links>를 클릭해보면 라우터는 <Route>에 맞는 페이지를 랜더링합니다.

     

    위의 예시에 사용된 컴포넌트들을 자세히 보겠습니다.

    Primary Components

    React Router의 컴포넌트는 크게 3가지로 나눌 수 있습니다.

     

    Routers

    • <BrowserRouter>
    • <HashRouter>

     

    Route Matchers

    • <Route>
    • <Switch>

     

    Navigation

    • <Link>
    • <NavLink>
    • <Redirect>

    Routers

    프로젝트에 react-router을 적용하기 위해서는 엘리먼트 계층중의 root에 렌더링이 되도록 설정해야합니다. 이 때문에 대부분 아래와 같이 <App> 엘리먼트를 감싸도록 작성합니다.

     

    src/index

    import React from "react";
    import ReactDOM from "react-dom";
    import { BrowserRouter } from "react-router-dom";
    
    import "./index.css";
    import App from "./App";
    
    ReactDOM.render(
      <BrowserRouter>
        <App />
      </BrowserRouter>,
      document.getElementById("root")
    );

     

    <BrowserRouter>와 <HashedRouter>의 차이는 무엇일까요?

     

    BrowserRouter

    <BrowserRouter>은 우리가 흔히 사용하는 URL를 사용합니다.  URL를 사용하여 서버와 소통할 수 있으며, HTML5의 History API를 사용하여 페이지를 새로고침하지 않고도 주소를 변경할 수 있습니다.

     

    HashedRouter

    그 반면 <HashedRouter>을 사용하면 URL에 http://localhost:3000/#/users 이렇게 '#(해쉬)'를 발견할 수가 있습니다. 해쉬는 서버에 보내지지 않기에 서버와의 소통이 불가합니다. 그 때문에 주로 정적인 페이지를 작성할 때 사용합니다. 

    Route Matchers

    Route Matchers 컴포넌트에는 Switch와 Route가 있습니다. Switch 컴포넌트는 여러 Route를 감싸서 그 중 제일 처음 매칭되는 하나의 라우트만을 렌더링합니다. 만약에 맞는 Route가 없다면 Switch는 null을 렌더링합니다.

     

    <Route path>의 특징

    <Route>의 path는 전체 값이 정확히 일치하는지를 보지 않고 URL의 시작부터 매칭을 합니다. 그렇기 때문에 언제나 <Route path="/">와는 항상 매칭할 수밖에 없습니다. 

     

    띠라서 아래의 경우와 같이 <Route path="/">를 가장 위에 작성했다면 /about과 /users으로 이동이 불가능합니다.

    <Switch>
      <Route path="/">
        <Home />
      </Route>
      <Route path="/about">
        <About />
      </Route>
      <Route path="/users">
        <Users />
      </Route>
    </Switch>;

    확인해보시면 아래와 같이 작동이 안되는 것을 알 수가 있습니다.

     

    이를 해결하기 위해 2가지 방법이 있습니다.

     

    첫번째 방법은 exact를 사용하는 것입니다.

    <Switch>
      <Route path="/" exact>
        <Home />
      </Route>
      <Route path="/about">
        <About />
      </Route>
      <Route path="/users">
        <Users />
      </Route>
    </Switch>;

    exact 속성을 주면 주어진 path값과 완벽히 일치해야 이동할 수 있도록 제한할 수 있습니다.

     

    두번째 방법은 가장 아래에 두는 것입니다.

    <Switch>
      <Route path="/about">
        <About />
      </Route>
      <Route path="/users">
        <Users />
      </Route>
      <Route path="/">
        <Home />
      </Route>
    </Switch>;

    가장 아래에 두면 path="/"를 가장 마지막에 찾기 때문에 이를 방지할 수가 있습니다.

    Navigation

    <Link>

    리액트 라우터는 <Link>컴포넌트를 통해 다른 주소로 이동시켜 줄 수 있는 링크를 생성할 수 있습니다. <Link> 사용 시 HTML 다큐먼트에 <a>태그를 랜더링하여 사용합니다. 그러나 우리가 흔히 사용하는 <a>태그와 다르게 페이지 전환을 방지하는 기능을 내장하고 있어 페이지를 새로 부르지 않고 페이지의 주소만 변경하도록 합니다.

     

    <NavLink>

    <NavLink>는 <Link>와 같습니다만 "active" 상태일 때 스타일링을 할 수 있는 <Link>입니다.

    아래와 같이 activeClassName을 주어 active 상태일 때 해당 css가 적용할 수 있습니다.

    <NavLink to="/react" activeClassName="hurray">
      React
    </NavLink>

     

    또는 아래와 같이 activeStyle로 직접 active 상태일 때의 css를 줄 수가 있습니다.

    <NavLink
      to="/faq"
      activeStyle={{
        fontWeight: "bold",
        color: "red"
      }}
    >
      FAQs
    </NavLink>

    

    <Redirect>

    <Redirect>는 강제로 해당 주소로 이동을 시킵니다.

    <Route exact path="/">
      {loggedIn ? <Redirect to="/dashboard" /> : <PublicHomePage />}
    </Route>

    위와 같이 특정 조건에 강제로 다른 주소로 이동 시킬 때 사용할 수가 있습니다.

     

    예시 2 :  Nested 라우팅

    import React from "react";
    import {
      BrowserRouter as Router,
      Switch,
      Route,
      Link,
      useRouteMatch,
      useParams
    } from "react-router-dom";
    
    export default function App() {
      return (
        <Router>
          <div>
            <ul>
              <li>
                <Link to="/">Home</Link>
              </li>
              <li>
                <Link to="/about">About</Link>
              </li>
              <li>
                <Link to="/topics">Topics</Link>
              </li>
            </ul>
    
            <Switch>
              <Route path="/about">
                <About />
              </Route>
              <Route path="/topics">
                <Topics />
              </Route>
              <Route path="/">
                <Home />
              </Route>
            </Switch>
          </div>
        </Router>
      );
    }
    
    function Home() {
      return <h2>Home</h2>;
    }
    
    function About() {
      return <h2>About</h2>;
    }
    
    function Topics() {
      let match = useRouteMatch();
    
      return (
        <div>
          <h2>Topics</h2>
    
          <ul>
            <li>
              <Link to={`${match.url}/components`}>Components</Link>
            </li>
            <li>
              <Link to={`${match.url}/props-v-state`}>
                Props v. State
              </Link>
            </li>
          </ul>
    
          {/* The Topics page has its own <Switch> with more routes
              that build on the /topics URL path. You can think of the
              2nd <Route> here as an "index" page for all topics, or
              the page that is shown when no topic is selected */}
          <Switch>
            <Route path={`${match.path}/:topicId`}>
              <Topic />
            </Route>
            <Route path={match.path}>
              <h3>Please select a topic.</h3>
            </Route>
          </Switch>
        </div>
      );
    }
    
    function Topic() {
      let { topicId } = useParams();
      return <h3>Requested topic ID: {topicId}</h3>;
    }

     

    위의 예시는 Topics 함수와 Topic 함수에 주목하시면 됩니다. /Topics 라우트는 Topics 컴포넌트를 paths :id 값에 따라 조건적으로 렌더링합니다.

     

     

    위에 새로 사용한 useRouteMatch와 useParams에 대하여 알아보도록 하겠습니다.

    useRouteMatch()

    useRouteMatch 훅을 사용하면 match 오브젝트에 손쉽게 접근할 수가 있습니다.

     

    match는 무엇일까요? 

    match는 <Route path>가 어떻게 URL과 매칭이 되었는지에 관한 정보를 담은 오브젝트입니다. 

     

    match는 아래의 값을 지니고 있습니다.

    • path : [string] 매칭에 사용된 path 패턴
    • url : [string] 매칭에 사용된 url 부분
    • isExact : [boolean] 전체 경로가 완전히 매칭할 때 true 반환 
    • params : [JSON object] url path로 전달된 파라미터 객체 

    덕분에 match 오브젝트를 통해 url 및 파라미터 값을 손쉽게 접근할 수 있습니다.

     

    사실 match와 같은 부가적인 정보를 지닌 오브젝트는 2개 더 있습니다. 위의 예제와 상관없지만 react-router을 구성하는 중요 오브젝트들이니 알아보도록 하겠습니다.

     

    history

     

    history 오브젝트는 현재까지 이동한 경로를 저장한 오브젝트입니다. 해당 오브젝트를 통해 특정 버튼을 눌렀을 시 뒤로 가거나, 로그인 후 화면을 전환할 때 등에 history를 활용할 수가 있습니다.

     

    hisory는 아래의 값을 지닙니다.

     

    • length : [number] 전체 history 스택의 길이
    • action : [string] 최근에 수행된 action (PUSH, REPLACE or POP)
    • location : [JSON object] 최근 경로 정보
    • push(path, [state]) : [function] 새로운 경로를 history 스택으로 푸시하여 페이지를 이동
    • replace(path, [state]) : [function] 최근 경로를 history 스택에서 교체하여 페이지를 이동
    • go(n) : [function] : history 스택의 포인터를 n번째로 이동
    • goBack() : [function] 이전 페이지로 이동
    • goForward() : [function] 앞 페이지로 이동
    • block(prompt) : [function] history 스택의 PUSH/POP 동작을 제어

     

    사용예시

    • block 메서드를 통하여 해당 페이지를 떠날 시 '정말로 떠나겠습니까?'와 같은 문구가 나타나도록 할 수 있습니다.
    • push 메서드를 통하여 다른 경로로 이동할 수 있습니다.
    • goBack goForward 메서드를 통해 전 후 페이지를 다시 찾아 갈 수 있습니다.

     

    Hook

    let history = useHistory();

    history 또한 match와 마찬가지로 훅을 통해 접근할 수가 있습니다.

     

    location

     

    location 오브젝트는 현재 페이지에 대한 정보를 지닙니다.

     

    location은 아래의 값을 지닙니다.

     

    • pathname : [string] 현재 페이지의 경로명
    • search : [string] 현재 페이지의 query string
    • hash : [string] 현재 페이지의 hash

     

    사용예시

    • location은 아래와 같이 <Link to>에 사용도 가능하며 history에 location 값을 넣을 때도 사용합니다.
    const location = {
      pathname: '/somewhere',
      state: { fromDashboard: true }
    }
    
    <Link to={location}/>
    <Redirect to={location}/>
    history.push(location)
    history.replace(location)

    Hook

    let location = useLocation();

     

    location 또한 useLocation() 훅을 통해 접근할 수가 있습니다.

     

    useParams()

    useParams() 훅은 url 파라미터를 key/value 페어 형태인 오브젝트를 반환합니다.

     

    참고자료

     

    React | Router : match, location, history

    Router Props  브라우저와 리액트앱의 라우터를 연결하게 되면 그 결과 라우터가 history api에 접근할 수 있게 되며 각각의 Route와 연결된 컴포넌트에 props로 match, location, history라는 객체를 전달하게..

    gongbu-ing.tistory.com

     

    React Router: Declarative Routing for React

    Learn once, Route Anywhere

    reactrouter.com

     

    '리액트' 카테고리의 다른 글

    [넘블 챌린지] 색깔 찾기 게임 만들기  (0) 2022.02.13
    클래스101 클론 후기  (0) 2022.01.16
    ref & useRef() & forwardRef()  (0) 2021.09.11
    Portals  (0) 2021.09.08
    Context  (0) 2021.09.05
Designed by Tistory.