あの日見たreact-routerの魅力を僕たちはまだ知らない(v5)

##はじめに

参考になった記事:
[react-router@v4を使ってみよう：シンプルなtutorial](
https://qiita.com/muijp/items/b4ca1773580317e7112e#%E4%BB%8A%E5%9B%9E%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84api)
公式サイト:
https://reacttraining.com/react-router/web/guides/quick-start

なお、この記事を書いている私は、経験が浅いのであんまり参考にしないほうがいいかもしれません。
逆に「ここ間違ってるよ！」「ここもっとこうした方がいい！」というのがあればぜひ教えて下さい。


##書くこと&書かないこと
react-routerを実際に使ってみて、「これは使える！」と思った機能をご紹介します。
ユースケース別にまとめつつ割と実用的なことを書きます。
react-routerについての概要は、先にご紹介させていただい[@muijpさんの記事](http://...)がめっちゃわかりやすいので、公式とあわせてぜひ御覧ください。
以下の記事はは現時点2020/2での最新版v5.1.2に対応しています。

#ケース①：「URLがちゃいまっせ！」って言いたい。
<img width="475" alt="スクリーンショット 2020-02-02 16.21.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487370/638100d3-68e7-a59d-7807-95759e5c9dee.png">

↑のようなイメージ
正しいurlは"about"だが、"abou"と入力してしまったので「ちゃいまっせ！」っていう。
URLをべた打ちするユーザーは少ないだろうし、個人サイトならまぁやんなくてもいいっちゃいい。
ただどっか自分がLink先のURLを書き間違えてたときなどの保険にはなるのでやっておくにこしたことはないと思う。


```react:App.jsx
import React from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Redirect,
} from 'react-router-dom';
import Home from 'components/pages/Home';
import About from 'components/pages/About';
import NotFoundPage from 'components/pages/NotFoundPage';

const App = ({ authState }) => {
  return (
    <Router>
      <Switch>
        <Route path="/" exact component={Home} />
        <Route path="/about" component={About} />
        <NotFoundPage />
      </Switch>
    </Router>
  );
};

export default App;
```

```react:NotFoundPage.jsx
import React from 'react';
import { Route, useLocation } from 'react-router-dom';
import Layout from 'components/organisms/Layout';

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

  return (
    <Route
      path="*"
      render={() => (
        <Layout>
          <h1>
            <code>{location.pathname}</code>が見つかりませんでした。
          </h1>
        </Layout>
      )}
    />
  );
};

export default NotFoundPage;
```

react-router公式の
https://reacttraining.com/react-router/web/example/no-match
https://reacttraining.com/react-router/web/api/Hooks/uselocation
を見ながら作成した。
ポイントはpath="*"のページをRouterの一番最後に置くことで、
上記以外ならURLが間違ってまっせ！ってできること。
ちなみにuseLocationを使うことで、現在のURLのlocationがわかる。
ここではuseLoacationを使って
"`https://livrio.firebaseapp.com/abou`"の”abou”の部分をh1で表示している。



#ケース②：「ログインしないと見れませんぜ兄貴！」って言いたい。


<img width="573" alt="スクリーンショット 2020-02-02 16.36.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487370/3e7ce4c7-fb1e-ec92-bc56-fd3e3ad95109.png">

↑のようなことをやりたい。
他のページが見たかったのにいきなりログインページが現れたら、
「なんなん？急にどした？」ってなるユーザももしかするといるかもしれない。
これもなくてもいいっちゃいいが、教えてあげるのがやはり丁寧だ。


```react:App.jsx
import React from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Redirect,
} from 'react-router-dom';
// route components
import Home from 'components/pages/Home';
import About from 'components/pages/About';
import MyPage from 'components/pages/MyPage';
import LogIn from 'containers/pages/LogIn';

const App = ({ authState }) => {
  return (
    <Router>
      <Switch>
        <Route path="/" exact component={Home} />
        <Route path="/about" component={About} />
        <Route
          path="/my-page"
          render={() =>
            authState === true ? (
              <MyPage />
            ) : (
              <Redirect to={{ pathname: '/login', state: '/my-page' }} />
            )
          }
        />
        <NotFoundPage />
      </Switch>
    </Router>
  );
};

export default App;

```
```react:App.jsx
import React from 'react';
import { useLocation, Redirect } from 'react-router-dom';
import Layout from 'components/organisms/Layout';

const LogIn = ({ authState, onLogIn }) => {
  const location = useLocation();
  const FromGuardPages = () => {
    if (location.state === '/my-page') {
      return (
      <Layout>
        <h1>
          We are sorry...MyPageを見るにはログインが必要です。
        </h1>
      </Layout>
      );
    }
    return null;
  };
  if (authState === true) {
    return <Redirect to="/" />;
  }

  return (
    <Layout>
        <FromGuardPages />
        <div>
          ここにログインのためのコード（今回は省略）
        </div>
    </Layout>
  );
};

export default LogIn;
```



react-router公式の以下を見ながら作成した。
https://reacttraining.com/react-router/web/example/auth-workflow

Redirectは特定の遷移（SPAなので遷移って言わないかもだけど）させるだけではなく、
任意の情報を持たせつつ遷移させることができる。
上の例ではpathnameに遷移先のURLを書きつつ、stateに遷移元の情報を渡している。
logInの側では、stateに渡した情報を参照して、特定の条件当てはまったときにメッセージを表示させる。
ログインしている状態になったらホームに自動的に移動するようにしてある。

#ケース③：「ばっちりでっせ兄貴、親方んとこ戻りましょうや！」って言いたい。

<img width="809" alt="スクリーンショット 2020-02-02 17.51.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487370/48df2a84-bff3-6512-07a6-b4deacc8a0c1.png">
↑borrowを押すと、↓マイページに遷移。
<img width="700" alt="スクリーンショット 2020-02-02 17.52.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487370/3878382d-f747-952b-94f6-950560b8016f.png">

```react:BookDetail.jsx
import React, { useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import BorrowButton from 'components/molecules/BorrowButton';

const FetchedDetail = ({onBorrow}) => {
  const history = useHistory();
  const handleClick = () => {
    onBorrow();
    history.push('/my-page');
  };

  return (
    <ShouldLoading isLoading={isLoading}>
      <Layout>
             {...省略}
              <BorrowButton
                borrowing={fetchedDetail.borrowing}
                onClick={handleClick}
              />
      </Layout>
  );
};

export default FetchedDetail;
```

react-routerの遷移は、基本的にはLinkを使う。
しかし、同時に他のアクションをしつつ遷移させたい、スナックバーで「サクセス！」というメッセージを出してから遷移したい、といったケースではuseHistoryを使うと幸せになれるのかもしれない。


#ケース④：「今日もばっちりキマってまんなぁ兄貴！」って言われたい。（願望）
<img width="472" alt="スクリーンショット 2020-02-02 18.14.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487370/5d6c65b8-6136-6921-27f8-a01f9538a648.png">

↑のように現在のURLをグレーにして、他をピンクっぽい紫色にしたい。


```react:NavMenu.jsx
import React from 'react';
import { NavLink } from 'react-router-dom';
import styled from 'styled-components';
import { theme, Divider, Text } from 'components/atoms';

const Menu = () => {
  const navItems = [
    {
      value: 'Home',
      link: '/',
      border: theme.light,
    },
    {
      value: 'MyPage',
      link: '/my-page',
      border: theme.naturalDark,
    },
    {
      value: 'About',
      link: '/about',
      border: theme.light,
    },
  ];

  return (
    <>
        {navItems.map(navItem => {
          return (
            <div key={navItem.link}>
              <Text
                className="body1"
                color={theme.secondary}
                as={NavLink}
                exact
                activeStyle={{ color: theme.naturalDark, cursor: 'default' }}
                to={navItem.link}
              >
                {navItem.value}
              </Text>
              <Divider color={navItem.border} />
            </div>
          );
        })}
    </>
  );
};

export default NavMenu;
```

```react:Text.jsx
import styled from 'styled-components';
import { theme } from 'components/atoms/theme';

export const Text = styled.span`
  color: ${props => props.color || theme.dark};
  &.body1 {
    font-weight: 400;
    font-size: 1rem;
    line-height: 1.5;
    letter-spacing: 0.00938em;
  }
```

下記を参照。
https://styled-components.com/docs/basics#getting-started
↑Styling any componentの項目にreact-routerとの連携が書いてあります。
https://reacttraining.com/react-router/web/api/NavLink/activestyle-object

styled-componentsを使うと、react-routerのLinkのスタイルを好きにいじれる。
例のようにasの中身にNavLinkやLinkを入れ込むことで、「見た目はTextだけど、機能はNavLink(またはLink)と一緒やで！」のようなことができる。

また、react-routerのNavLinkを使うと、toの中身と現在のURLがマッチしたときのスタイルをactiveStyleに書くことができる。
この場合、MyPageのNavLinkのみ、現在のURLのパラメーター(MyPage)とtoの中身(MyPage)が一致するため、activestyleが適応される。その結果、MyPageだけが灰色でマウスカーソルがポインターにならないようになる。

##終わり

以上です。
間違いがございましたら、ご指摘いだだけると嬉しいです。
最後までお読みいただきありがとうございました！