Reactでいい感じのページ遷移を実装してみよう！

react-router-domとframer-motionを組み合わせていい感じのページ遷移を
実装できたので記事にします！

# 今回の目的
下のいい感じのページ遷移を実装！
![Videotogif (3).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606623/0f1c175a-e2c5-7916-0866-e09db3c49fe0.gif)

# 前提
React + typeScriptのプロジェクトを作成できる環境を作成できること
## プロジェクト作成

```
create-react-app page-motion-sample-app --typescript
```

##　必要なパッケージのインストール

```
yarn add react-router-dom
yarn add @material-ui/core
yarn add framer-motion
```

## ページを作成
src配下にpagesフォルダを作成して、今回使用するページを作成


### src/pages/Left.tsx

``` react
import React from "react";

const Left = () => {
  return (
    <div>
      <div
        style={{
          width: "100%",
          height: 800,
          background: "chocolate",
          textAlign: "center"
        }}
      >
        左
      </div>
    </div>
  );
};

export default Left;
```

### src/pages/Under.tsx

``` react
import React from "react";

const Under = () => {
  return (
    <div>
      <div
        style={{
          width: "100%",
          height: 800,
          background: "antiquewhite",
          textAlign: "center"
        }}
      >
        下
      </div>
    </div>
  );
};

export default Under;
```

### src/pages/Right.tsx

``` react
import React from "react";

const Right = () => {
  return (
    <div>
      <div
        style={{
          width: "100%",
          height: 800,
          background: "aqua",
          textAlign: "center"
        }}
      >
        右
      </div>
    </div>
  );
};

export default Right;

```

## ルーティング作成
src/App.tsx　のファイルを下記の様に変更

``` react
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import None from "./pages/None";
import Left from "./pages/Left";
import Right from "./pages/Right";
import Under from "./pages/Under";

const App: React.FC = () => {
  return (
    <div className="App">
      <Router>
        <main role="main" className="pt-5">
          <Switch>
            <Route exact path="/" component={None} />
            <Route exact path="/left" component={Left} />
            <Route exact path="/right" component={Right} />
            <Route exact path="/under" component={Under} />
          </Switch>
        </main>
      </Router>
    </div>
  );
};

export default App;
```

## 移動用のナビバーを作成

src配下にcomponentsフォルダを作成して、ナビバーを作成

src/components/NavBar.tsx

``` react 
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import BottomNavigation from "@material-ui/core/BottomNavigation";
import BottomNavigationAction from "@material-ui/core/BottomNavigationAction";
import ArrowForward from "@material-ui/icons/ArrowForward";
import ArrowBack from "@material-ui/icons/ArrowBack";
import ArrowDownward from "@material-ui/icons/ArrowDownward";
import { Grid } from "@material-ui/core";
import { withRouter } from "react-router";

const useStyles = makeStyles({
  root: {
    width: 500
  }
});

const NavBar = (props: any) => {
  const classes = useStyles();
  const [value, setValue] = React.useState(0);

  return (
    <Grid container alignItems="center" justify="center">
      <BottomNavigation
        value={value}
        showLabels
        className={classes.root}
        style={{
          width: "100%"
        }}
      >
        <BottomNavigationAction
          label="左"
          icon={<ArrowBack />}
          onClick={() => {
            props.history.push("/left");
          }}
        />
        <BottomNavigationAction
          label="下"
          icon={<ArrowDownward />}
          onClick={() => {
            props.history.push("/under");
          }}
        />
        <BottomNavigationAction
          label="右"
          icon={<ArrowForward />}
          onClick={() => {
            props.history.push("/right");
          }}
        />
      </BottomNavigation>
    </Grid>
  );
};

export default withRouter(NavBar);
```

## NabBarを各Pageに組み込む
こんな感じで上で作成したNabBarを全ページに組み込んでいきます

``` react 
import React from "react";
{/*  ここから */}
import NavBar from "../components/NavBar";
{/*  ここからここまで追加 */}

const Left = () => {
  return (
    <div>
      {/*  ここから */}
      <NavBar />
      {/*  ここからここまで追加 */}
      <div
        style={{
          width: "100%",
          height: 800,
          background: "chocolate",
          textAlign: "center"
        }}
      >
        左
      </div>
    </div>
  );
};

export default Left;
```

ここまで組み込むと最低限動く形になりました！
![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606623/7a84265c-da9d-3d9b-c29b-7e2f55f59cc8.gif)

# 次は動きを追加します！

## ページ遷移時に動きをつけるファイルを作成

src/components/motion配下に、ページ遷移時に動きをつけるファイルを作成

### src/components/motion/LeftMotion.tsx

``` react 
import React from "react";
import { motion } from "framer-motion";

const LeftMotion: React.FC<{
  children: JSX.Element;
}> = ({ children }) => {
  return (
    <motion.div
      animate={{
        x: 0,
        opacity: 1
      }}
      initial={{
        x: -500,
        opacity: 0
      }}
      exit={{
        x: 0,
        opacity: 0
      }}
      transition={{
        duration: 0.3
      }}
    >
      {children}
    </motion.div>
  );
};

export default LeftMotion;
```

### src/components/motion/RightMotion.tsx

``` react
import React from "react";
import { motion } from "framer-motion";

const RightMotion: React.FC<{
  children: JSX.Element;
}> = ({ children }) => {
  return (
    <motion.div
      animate={{
        x: 0,
        opacity: 1
      }}
      initial={{
        x: 500,
        opacity: 0
      }}
      exit={{
        x: 0,
        opacity: 0
      }}
      transition={{
        duration: 0.3
      }}
    >
      {children}
    </motion.div>
  );
};

export default RightMotion;
```

### src/components/motion/UnderMotion.tsx

``` react
import React from "react";
import { motion } from "framer-motion";

const UnderMotion: React.FC<{
  children: JSX.Element;
}> = ({ children }) => {
  return (
    <motion.div
      animate={{
        y: 0,
        opacity: 1
      }}
      initial={{
        y: 500,
        opacity: 0
      }}
      exit={{
        y: 0,
        opacity: 0
      }}
      transition={{
        duration: 0.3
      }}
    >
      {children}
    </motion.div>
  );
};

export default UnderMotion;
```

## ページ遷移時の動きを各Pageに組み込む
こんな感じで上で作成したファイルを全ページに組み込んでいきます

``` react
import React from "react";
{/* ここから */}
import UnderMotion from "../components/motion/UnderMotion";
{/* ここまで変更 */}
import NavBar from "../components/NavBar";

const Under = () => {
  return (
    <div>
      <NavBar />
      {/* ここから */}
      <UnderMotion>
        <div
          style={{
            width: "100%",
            height: 800,
            background: "antiquewhite",
            textAlign: "center"
          }}
        >
          下
        </div>
      </UnderMotion>
      {/* ここまで変更 */}
    </div>
  );
};

export default Under;
```

上記の追加が終わればいい感じのページ遷移が確認できます！

![Videotogif (3).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606623/062003ab-1608-abed-70ab-1e73f76c8433.gif)

Gifがいまいちなので実際の動きを正確に確認したい方は、GitHubからコードを落として確認してください！
https://github.com/aokisinn/page-motion-sample-app

あと、Macでいい感じのGif作成できるアプリ知っている方いたらコメントで教えてください！！！