> For the complete documentation index, see [llms.txt](https://shhn0509.gitbook.io/react/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://shhn0509.gitbook.io/react/react-router/basic-routing.md).

# 기본 라우팅

## React Router 모듈

```javascript
import { 
  BrowserRouter as Router, 
  // 또는 HashRouter as Router, 
  Switch,
  Route, 
  Link,
  NavLink,
  Redirect
} from 'react-router-dom';
```

## Router 컴포넌트

#### BrowserRouter 컴포넌트

* HTML5 History API를 사용해 URL과 매칭되는 UI를 렌더링한다. (예: `/lectures`)
* 해시값 없이 `pathName`을 사용해서 이동한다.&#x20;
* IE10+ 부터 사용 가능하다.&#x20;

#### HashRouter 컴포넌트

* URL 해시(`#`)를 사용해 URL과 UI를 매칭한다. (예: `/#/lectures`)
* 검색 엔진이 읽지 못한다.&#x20;
* URL 해시를 사용하기 때문에 브라우저나 웹 서버에 제한 없이 사용할 수 있다.&#x20;

```javascript
// 예시 
example.com/#/messages/messages
```

```javascript
<HashRouter hashType="hashbang">
```

{% hint style="info" %}
[GitHub Pages](https://pages.github.com/)에 React 앱을 배포할 경우, HashRouter를 사용해야 한다. \
참고 → [HashRouter과 BrowserRouter의 차이](https://wonit.tistory.com/299)&#x20;
{% endhint %}

### 라우터 설정

일반적으로 라우터는 App 컴포넌트에 추가한다. 라우터 내부에는 각 라우트 경로와 연결 될 컴포넌트를 설정하고, 각 페이지를 탐색하게 하는 내비게이션으로 구성된다. &#x20;

```javascript
const App = () => (
  <Router>
    {/* 내비게이션: <Link>, <NavLink> 사용 */}
    {/* 라우트: <Swtich>, <Router>, <Redirect> 사용 */}
  </Router>
)
```

또는 ReactDOM 렌더링 과정에서 `<Router>`로 `<App>`을 래핑할 수 있다. &#x20;

```javascript
ReactDOM.render(<Router><App/></Router>, document.getElementById('reactApp'));
```

## React Router 컴포넌트 종류

React 웹 앱 제작에 자주 사용되는 컴포넌트&#x20;

| 컴포넌트 종류                                                                                                                                                                                                         | 설명                                  |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- |
| `<BrowserRouter>` / `<HashRouter>`                                                                                                                                                                              | 라우터(Router) 컴포넌트                    |
| [`<Route>`](https://reacttraining.com/react-router/web/api/Route)/  [`<Switch>`](https://reacttraining.com/react-router/web/api/Switch)                                                                         | 라우트 경로(Route Path) 매처(matcher) 컴포넌트 |
| [`<Link>`](https://reacttraining.com/react-router/web/api/Link)/ [`<NavLink>`](https://reacttraining.com/react-router/web/api/NavLink)/ [`<Redirect>`](https://reacttraining.com/react-router/web/api/Redirect) | 라우트를 변경하는 내비게이션(Navigation) 컴포넌트    |

## Route 컴포넌트

[Route ](https://reacttraining.com/react-router/web/api/Route)컴포넌트는 설정된 `path`와 매칭되는 컴포넌트를 찾아 일부 UI를 렌더링 한다. 일반적으로 라우트는 `path`, `component` 속성을 사용해 표시 할 URL과 컴포넌트를 설정한다. &#x20;

### path / component 속성 &#x20;

`path` 속성의 값과 매치되는 경로로 이동한다. 이때 `path="/"` 경우 `exact` 키워드를 같이 사용해야한다. `exact`는 정확하게 검사한다는 의미로 이를 설정하지 않으면 `/lecture` 페이지에서 `/`(Home) 페이지의 콘텐츠도 같이 보이는 오류가 발생한다. &#x20;

```javascript
import Home from './views/Home'
import Lecture from './views/Lecture'
import Lab from './views/Lab'

<BrowserRouter>
  <Route path="/" exact component={Home} />
  <Route path="/lecture" component={Lecture} />
  <Route path="/lab" component={Lab} />
</BrowserRouter>
```

`component` 속성을 사용하지 않으면 아래와 같이 작성한다.&#x20;

```javascript
<BrowserRouter>
  <Route path="/" exact>
    <Home />
  <Route>
  <Route path="/lecture">
    <Lecture />
  <Route>
  <Route path="/lab">
    <Lab />
  <Route>
</BrowserRouter>
```

### Route 컴포넌트 렌더링 방법

`<Route>` 컴포넌트를 사용해 렌더링 하는 방법은 다음의 3가지 이다.&#x20;

| 렌더링 방법                                                                                      | 설명                             |
| ------------------------------------------------------------------------------------------- | ------------------------------ |
| [`<Route component>`](https://reacttraining.com/react-router/web/api/Route/component)       | URL과 매칭되는 컴포너트를 렌더링 한다.        |
| [`<Route render>` 함수](https://reacttraining.com/react-router/web/api/Route/render-func)     | 인라인 렌더링 또는 래핑 렌더링 시에 사용한다.     |
| [`<Route children>` 함수](https://reacttraining.com/react-router/web/api/Route/children-func) | 매칭될 경우, 자식 컴포넌트를 렌더링 할 때 사용한다. |

#### **component** 렌더링

위에서 본 component  속성을 사용해서 렌더링 하는 방식이다.&#x20;

```javascript
<Route 
  path="/" 
  component={Home} 
/>
```

#### **render** 함수 렌더링

* 인라인 렌더링 → render 함수의 반환 값으로 컴포넌트를 내보내는 방식이다. 단, 개발자 도구에서 확인이 불가능하다. (권장 X)&#x20;
* render가 전달 받는 인자는 Route 컴포넌트가 전달 받은 props(match, location, history)를 전달 받는다.&#x20;

```javascript
// 인라인 렌더링
<Route 
  path="/" 
  exact 
  render={() => <div className="Home">홈</div>} 
/>

// 래핑 렌더링
const FadeInRoute = (({component: Component, ...rest}) => {
  return (
    <Route 
      {...rest}
      // render의 routeProps는 Route컴포넌트에 전달된 ...rest를 전달 받는다.
      render={(routeProps) => (
        <FadeIn>
          <Component {...routeProps} />
        </FadeIn>
      )}
    />
  )
}

<FadeInRoute path="/lab" component={Lab} />
```

**children** 함수 렌더링

**children** 함수 렌더링 방식은 RouteGuard와 같이 애니메이션 라우트를 만들 때 사용할 수 있다. 그래서 path속성을 사용한 일반적인 라우트에서는 사용하지 않는다.&#x20;

```javascript
<Route
  children={({ match, ...rest }) => (
    {/* Animate는 항상 렌더링되므로 라이프 사이클 훅을 사용하여 
        자식(child) 컴포넌트를 애니메이션 할 수 있습니다. */}
    <Animate>
      {match && <SubPage {...rest}/>}
    </Animate>
  )}
/>
```

{% hint style="info" %}
React에서 애니메이션 기능을 구현하기 위해서 [React Spring](https://www.react-spring.io/)과 같은 애니메이션 전용 라이브러리를 사용할 수 있다.&#x20;
{% endhint %}

## Route 컴포넌트의 Props

* [match](https://reacttraining.com/react-router/web/api/match)
* [location](https://reacttraining.com/react-router/web/api/location)
* [history](https://reacttraining.com/react-router/web/api/history)

#### Route 컴포넌트 props 전달

Route 컴포넌트에 props를 전달 할 때는 render 속성을 사용해서 props를 전달한다.&#x20;

Categorise 컴포넌트에 sortBy 속성을 전달하기 위해 1번 코드와 같이 작성하면 match, location, history는 Categorise 컴포넌트에 전달 되지 않는다.&#x20;

```javascript
/*   1   */
<Route 
  path="/categories" 
  render={(props) => <Categories sortBy="createdAt" />} 
/>
```

하지만 아래와 같이 컴포넌트에 전달 받은 props를 전개해서 전달해 주면 해당 컴포넌트는 sortBy 속성을 포함한 match, location, history 속성도 모두 전달 받는다.&#x20;

```javascript
/*   2   */
<Route 
  path="/categories" 
  render={(props) => <Categories sortBy="createdAt" {...props} />} 
/>
```

### 정확한 라우팅 설정

홈 링크 패스 `/`는 항상 활성화 상태이다. 모든 패스에 `/`가 있기 때문이다. 그래서 다른 링크를 클릭해도 홈 UI는 항상 표시된다.  홈 링크에 `exact` 속성을 추가해 정확(exact)하게 패스가 일치할 때만 표시되도록 설정한다.&#x20;

```javascript
<NavLive to="/" exact>홈</NavLive>

<Route path="/" component={Home} exact />
```

{% hint style="info" %}
홈 링크를 설정할 땐 항상 exact를 설정하자!&#x20;
{% endhint %}

### 엄격한 경로 구분 설정

`strict` 속성이 설정된 경우, 현재 URL과 일치하는지 여부를 결정할 때 URL의 후미 슬래시를 고려한다.&#x20;

```javascript
<Route path="/one" exact strict>
  <Product />
</Route>
```

| 경로     | 경로 이름      | 매칭  |
| ------ | ---------- | --- |
| `/one` | `/one`     | 일치  |
| `/one` | `/one/`    | 불일치 |
| `/one` | `/one/two` | 불일치 |

#### 대소문자 구분 설정 <a href="#undefined" id="undefined"></a>

경로(path) 이름의 대소문자를 민감하게 구분하고자 한다면 `sesitive` 속성을 추가한다. &#x20;

```javascript
<Route path="/one" sensitive>
  <Product />
</Route>
```

| 경로     | 경로 이름  | 구분    | 매칭  |
| ------ | ------ | ----- | --- |
| `/one` | `/one` | true  | 일치  |
| `/One` | `/one` | true  | 불일치 |
| `/One` | `/one` | false | 일치  |

## Switch 컴포넌트&#x20;

자식 컴포넌트 중에 to나 path 값이 일치하면 그 곳에서 멈추고 들어간다. &#x20;

{% hint style="info" %}
Route 컴포넌트와 항상 같이 사용한다고 생각하기&#x20;
{% endhint %}

```javascript
<Switch> 
  <Route path="/about" component={About} />
  <Route path="/:user" component={User} />
  <Route path="*" component={NoMatch} />
</Switch>
```

## Link 컴포넌트

[Link](https://reacttraining.com/react-router/web/api/Link) 컴포넌트는 애플리케이션을 탐색하는 기능을 제공한다. `to` 속성 값으로 경로(path) 문자 값 또는 객체를 설정 할 수 있다. 네비게이션 처럼 클릭 했을 때 해당 패스로 이동하는 링크를 만드는 컴포넌트이다. to값과 일치하는 path로 이동한다.&#x20;

to 속성에 들어가는 값을 유형&#x20;

* string → 간단한 pathName일 때 사용한다.
* object → 객체 형식으로 path, search 등을 설정할 때 사용한다.&#x20;
* function → 중간에 source를 인터챕터(interchapter)하여 설정한다.&#x20;

#### Link 컴포넌트를 사용해서 props 내보내기&#x20;

to 속성에 객체 형식으로 담에서 보낼 수 있다.&#x20;

{% tabs %}
{% tab title="App.js" %}

```javascript
<Link
  to={{
    pathname: "/login",
    search: "?user=hanna&mento=yamoo",
    hash: "#router",
    state: {
      message: "로그인 링크를 통해 전달된 메세지",
      isAuthed: true
    }
  }}
>
```

{% endtab %}

{% tab title="SignInPage.js" %}

```javascript
export function SignInPage(props) {
  const { message, isAuthed } = props.location.state;
  console.log(message, isAuthed);
  return (
    <div>
      <p children={message}></p>
      <p
        children={
          isAuthed ? "로그인 사용자입니다." : "로그인 사용자가 아닙니다."
        }
      ></p>
    </div>
  );
}
```

{% endtab %}
{% endtabs %}

## NavLink 컴포넌트

* Link 컴포넌트에 스타일을 줄 수 있다.&#x20;
* 일반 Link와 다르게 aria-current 와 calss 속성이 추가 된다.&#x20;

즉, 활성화 된 상태 클래스 `active`가 자동으로 설정, 스타일링이 가능하다. Link 컴포넌트를 사용할 예정이라면 NavLink를 사용하는 것이 좋겠다.&#x20;

#### innerRef 설정 <a href="#innerref" id="innerref"></a>

React 앱(16+)에 React Router 5.1을 사용할 경우, 참조(ref)를 기본으로 `<a>`에 전달 하므로 [forwardRef](https://ko.reactjs.org/docs/forwarding-refs.html)를 별도로 설정할 필요가 없다. 일반 `ref` 속성을 사용하면 된다. &#x20;

```javascript
<Link
  to="/"
  innerRef={node => {
    // `node`는 마운트 된(mounted) DOM 요소를 참조하고,
    // 마운트가 해제 된 경우(unmount)는 null 입니다.
  }}
/>

<Link
  to="/"
  innerRef={node => { node.addEventListener('click', () => {node.style.color = '#a6cfff'})
  }}
/>
```

```javascript
class LinkRefDemo extends React.Component {
  
  anchorRef = React.createRef()

  render() {
    return (
      <Link to="/" innerRef={anchorRef} />
    )
  }

}
```

### 정확한 경로에서만 활성화

`exact` 속성은 경로가 정확히 일치할 때만 활성화 하도록 설정할 때 사용한다. 아래 코드 예시와 같이 `exact` 속성을 설정해야 `/lecture/chapter/*` 페이지에서 `/lecture` 경로의 내비게이션 링크가 활성화 되지 않는다.&#x20;

```javascript
<NavLink to="/lecture" exact>강의</NavLink>
<NavLink to="/lecture/chapter/1">1장</NavLink>
```

## Redirect 컴포넌트

여러 개의 Route를 설정 했으나 사용자가 사용자가 입력한 path와 일치하는 Route가 없다면 Redirect 컴포넌트에 설정된 to 속성 값으로 이동한다.&#x20;

아래의 예시 처럼 Redirect 컴포넌트를 사용할 수 있다. 페이지를 찾을 수 없다는 Route를 만들어 두고 알 수 없는 경로를 입력했을 때 사용자가 해당 페이지로 이동하여 오류임을 알 수 있도록 한다.&#x20;

사용자 경험을 위해 홈페이지로 이동할 수 있는 링크를 설정해준다.&#x20;

```javascript
<Route
  path="/page-not-found"
  render={() => {
    return (
      <div>
        <h1 lang="ko">페이지를 찾을 수 없습니다. 404</h1>
        <ZanzanNavLink to="/">홈 페이지로 돌아가기</ZanzanNavLink>
      </div>
    );
  }}
/>
<Redirect to="/page-not-found" />
```

#### from 속성&#x20;

Redirect의 from 속성의 값을 path로 검색했을 때 to에 설정된 path 값으로 이동한다.&#x20;

```javascript
// from : 문자열 설정
// url에 / 입력 시 /home으로 이동 
<Redirect exact from="/" to="/home" />
// url에 /users/:id 입력 시 /users/profile/:id으로 이동 
<Redirect from="/users/:id" to="/users/profile/:id" />
```

### example&#x20;

```javascript
// to : 문자열 설정
<Redirect to="/dashboard"/>

// to : 객체 설정
<Redirect to={{
  pathname: '/login',
  search: '?utm=your+file',
  state: {
    referrer: currentLocation
  }
}}/>

// push : 현재 history 항목을 바꾸지 않고, 새 항목 추가
<Redirect to="/dashboard" push />

// from : 문자열 설정
<Redirect from="/admin" to="/dashboard" />
<Redirect from="/users/:id" to="/users/profile/:id" />

// exact : 정확한 URL 매칭 설정
<Redirect exact from="/" to="/home" />

// strict : 엄격한 URL 매칭 설정
<Redirect strict from="/one/" to="/home" />

// sensitive : 대소문자  URL 매칭 설정
<Redirect sesitive from="/One/" to="/one" />
```

## Conclusion

{% tabs %}
{% tab title="index.js " %}
index.js(rootElement)에 라우터 설정  → Browser/HashRouter

```javascript
import { BrowserRouter as Router } from "react-router-dom";
import App from "./App";

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Router>
    <App />
  </Router>
);

```

{% endtab %}

{% tab title="App.js " %}

### 1. 모듈 불러오기&#x20;

* react-router-dom에서 사용할 컴포넌트를 불러 온다. → `Route`, `Redirect`&#x20;
* 페이지 모듈을 불러 온다.  → `HomePage`, `SignInPage`

```javascript
import React from "react";
import { Route, Redirect } from "react-router-dom";
import ZanzanNavLink from "./components/ZanzanNavLink";
import {
  // BrowsePage,
  HomePage,
  // ManageProfilePage,
  SignInPage
  // WatchPage
} from "./pages";

```

### 2.&#x20;

* NavLink 컴포넌트 사용자 정의 커스텀 사용 → ZanZanNavLink&#x20;
* NavLink 컴포넌트의 to 속성으로 경로 설정&#x20;

```javascript

export default function App() {

  return (
    <div className="App">
      <nav>
        <ZanzanNavLink exact to="/">
          홈
        </ZanzanNavLink>
      </nav>
      <Switch>
        <Route path="/" component={Home} exact /> 
        <Route path="/about" component={About} exact strict />
        <Route path="/:user" component={User} exact strict />
        <Route
          path="/page-not-found"
          render={() => <h1 lang="ko">페이지를 찾을 수 없습니다. 404</h1> }
        />
        <Redirect to="/page-not-found" />
      </Switch>
    </div>
  );
}
 
```

{% endtab %}

{% tab title="ZanzanNavLink.js" %}

{% endtab %}
{% endtabs %}
