React + Typescriptでポートフォリオを作ってみた

# 前置き
タイトルに書いてある通り、React + Typescriptでポートフォリオを作ってみました。
レスポンシブ対応とSPA(シングルページアプリケーション)対応を行っています。
この記事では公開までの過程を書いていきます。

# 完成品
[roottool's Portfolio](https://roottool.github.io/)
[ソースコード](https://github.com/roottool/roottool.github.io)

## PCサイズ
![PC_Top.PNG](https://qiita-image-store.s3.amazonaws.com/0/300336/92d6e83f-95cb-c55a-aece-c67f24c93a7a.png)

## スマートフォン、タブレットサイズ
![SmartPhone_Skills.PNG](https://qiita-image-store.s3.amazonaws.com/0/300336/cc51368a-2eb5-d8ad-e40d-91fcd76614e4.png)

# 開発環境
- Windows 10 Pro
- Visual Studio Code
- Node.js：v8.12.0
- npm: v6.4.1

# 使ったパッケージ
- react: v16.6.0
- react-icons: v3.2.2
- react-router-dom: v4.3.1
- reactstrap: v6.5.0
- typescript: v3.1.3
- bootstrap: v4.1.3
- gh-pages: v2.0.1

# きっかけ
[AngularでWebチャットアプリを作ってみた](https://qiita.com/roottool/items/87eaf7ddd1d9d15be951)ので次はReactを触れてみたいと思っていました。
[フロント未学習の大学生が1週間でVue.jsを使ったポートフォリオを作った話](https://qiita.com/plus_kyoto/items/a01578b782f17f573510)や[大学生がReactで1日でポートフォリオを作った話](https://qiita.com/Akatsuki_py/items/351fb3aff9bad73f0378)を見て、自分もポートフォリオを作ろうと思い立って作りました。

# 導入編
## `create-react-app`をインストールする
以下のコマンドで、グローバルにインストールします。

```
npm install -g create-react-app
```
`create-react-app`コマンドを使うことで、Reactアプリを簡単に作成することが出来ます。

## `create-react-app`コマンドでReactアプリを作成する
以下のコマンドで、Reactアプリの雛形を作成します。

```
create-react-app my-app --typescript
```
`--typescript`オプションを付けることで、TypescriptでReactアプリを作成することが出来ます。
`my-app`には、作成するアプリ名を入力してください。
コンポーネントやページを作成する際の拡張子は**tsx**になります。
(2018/12/5 追記)
[create-react-appのバージョンアップに伴い](https://github.com/facebook/create-react-app/releases/tag/v2.1.0)、Typescriptを使用する際のオプションが変わりました。

# 実装編
## TOPページを実装する
まずはReactアプリの根幹となる`App.tsx`のコードを以下に示します。

```App.tsx
import * as React from 'react';

import './App.css';

import Backdrop from './Components/Backdrop/Backdrop';
import Navbar from './Components/Navbar/Navbar';
import SideDrawer from './Components/SideDrawer/SideDrawer';

interface ISideDrawerState {
  isOpen: boolean;
}

class App extends React.Component<{}, ISideDrawerState> {
  constructor(props: {}) {
    super(props);
    this.state = {
      isOpen: false,
    };

    this.drawToggleClickHandler = this.drawToggleClickHandler.bind(this);
    this.backdropClickHandler = this.backdropClickHandler.bind(this);
  };

  public render() {
    let backDrop;

    if (this.state.isOpen) {
      backDrop = <Backdrop backdropClickHandler={this.backdropClickHandler} />;
    }

    return (
      <div className="App">
        <Navbar drawToggleClickHandler={this.drawToggleClickHandler} />
        <SideDrawer show={this.state.isOpen} drawToggleClickHandler={this.drawToggleClickHandler} />
        {backDrop}
      </div>
    );
  }

  private drawToggleClickHandler = () => {
    this.setState((prevState) => {
      return { isOpen: !prevState.isOpen };
    });
  };

  private backdropClickHandler = () => {
    this.setState({ isOpen: false });
  };
}

export default App;
```

### PropsとState
まず、`class App extends React.Component<{}, ISideDrawerState>`の`<{}, ISideDrawerState>`でPropsとStateを指定します。
PropsとStateは以下のようなものです。

- Props: 親コンポーネントから受け取る情報
- State: 自コンポーネントの状態

今回は最上位のコンポーネントなのでPropsは空を示す`{}`、Stateはサイドバーの表示状態を示す`isOpen`となります。

```App.tsx
interface ISideDrawerState {
  isOpen: boolean;
}
```
Typescriptで書く際は、PropsやStateを上記のようにインターフェイスとして定義しておくと管理がしやすいと思います。

### constructor()
```App.tsx
constructor(props: {}) {
    super(props);
  };
```
上記で、コンポーネントの初期化を行います。
`super(props)`で親コンポーネントから送られた情報を受け取ります。
`constructor`を書く際は必ず`super(props);`を書きましょう。
それと個人的な経験則ですが、`constructor`は省略可能ですがコンポーネント作成時に書くべきだと思います。
理由としては、コンポーネント初期化処理を一番意識するのはコンポーネント作成時であると実感したためです。
~~後から必要になった時、省略していた私は完全に存在を忘れてしばらく悩んでいました。~~

今回は他にも以下のことを行っています。

```App.tsx
    this.state = {
      isOpen: false,
    };
```
これは、Stateの初期化を行っています。ページを開いた時の初期状態ではサイドバーは閉じているので、`false`と設定しています。

```App.tsx
    this.drawToggleClickHandler = this.drawToggleClickHandler.bind(this);
    this.backdropClickHandler = this.backdropClickHandler.bind(this);
```
これは、`App.tsx`の下部で定義していたメソッドの`this`をバインドしています。
バインドを行わなければ、イベントのコールバック関数として使用した時に`this`を使用することが出来ません。

### render()
Typesciprtで定義する際は必ず`public render()`と、アクセス修飾子を付けましょう。書かないとエラーが出ます。
`render()`の`return ()`内にページやコンポーネントの構成を記述していきます。

```App.tsx
<SideDrawer show={this.state.isOpen} drawToggleClickHandler={this.drawToggleClickHandler} />
```
といったように、コンポーネントを追加していくことが出来ます。
`show={this.state.isOpen}`と`drawToggleClickHandler={this.drawToggleClickHandler}`は、PropsとしてSideDrawerコンポーネントに値を送っています。

### setState()
Steteの値を更新する時に使用します。

```App.tsx
  private drawToggleClickHandler = () => {
    this.setState((prevState) => {
      return { isOpen: !prevState.isOpen };
    });
  };
```
更新を行う前の状態を用いる際は、`prevState`を使用します。
上記では、三本線アイコンがクリックされた時のサイドバーの表示非表示をトグルで処理しています。

## SideNavBarを実装する
[スマートフォン、タブレットサイズ](#%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%83%95%E3%82%A9%E3%83%B3%E3%82%BF%E3%83%96%E3%83%AC%E3%83%83%E3%83%88%E3%82%B5%E3%82%A4%E3%82%BA)のような、ナビゲーションバーにある三本線アイコンをタップするとサイドバーがスライドする処理を実装します。
レスポンシブ対応を行うのでPCから見る時は、[PCサイズ](#pc%E3%82%B5%E3%82%A4%E3%82%BA)のように三本線アイコンを非表示にしてナビゲーションバーにリンクを載せます。
実装に関しては、[ReactJS - Build a Responsive Navigation Bar & Side Drawer Tutorial](https://www.youtube.com/watch?v=l6nmysZKHFU)を参考にしました。(※英語です)

### ナビゲーションバーを実装する
```Navbar.tsx
interface IProps {
    drawToggleClickHandler(): void,
}
```
`App.tsx`から送られてきたコールバック関数を受け取るので、インターフェイスでPropsの定義を行います。
定義したインターフェイスを基に`constructor(props: IProps)`で初期化を行います。

```Navbar.tsx
    public render() {
        return (
            <header className="navbar" style={{ padding: 0 }}>
                <nav className="navbar__navigation">
                    <div className="navbar__toggle-button" onClick={this.clickHandler}>
                        <IconContext.Provider value={{ color: "white", size: "1.5em" }}>
                            <MdMenu />
                        </IconContext.Provider>
                    </div>
                    <div>
                        <Link to="/" className="navbar__title">Portfolio</Link>
                    </div>
                    <div className="spacer" style={{ flex: 1 }} />
                    <div className="navbar__navigation-items">
                        <ul>
                            <Link to="/about">
                                <li>about</li>
                            </Link>
                            <Link to="/works">
                                <li>Works</li>
                            </Link>
                            <Link to="/skills">
                                <li>Skills</li>
                            </Link>
                        </ul>
                    </div>
                </nav>
            </header>
        );
    }

    private clickHandler() {
        this.props.drawToggleClickHandler();
    }
```
`App.tex`から受け取ったコールバック関数を実行するメソッドを作成し、三本線アイコンに対するクリックイベントに適用しています。
TSXでクラスを定義する時は、`class`ではなく`className`で指定します。
TSXでクリックなどのイベントを定義する時は、`onClick`のようにキャメルケースで指定します。

`style={{}}`で個別にスタイル定義を行っています。
理由はコンポーネントのcssファイルに記載した定義ではなく、Bootstrapのスタイル定義が反映されていたのでTSX内に定義して対応したためです。

レスポンシブ対応を行うため三本線アイコンとナビゲーションバーの各項目は、CSSの`@media`で画面サイズに応じて表示非表示を切り替えています。

```Navbar.css
@media (max-width: 768px) {
    .navbar__navigation-items {
        display: none;
    }
}

@media (min-width: 769px) {
    .navbar__toggle-button {
        display: none;
    }

    .navbar__title{
        padding: 0 0rem;
    }
}
```

### サイドバーを実装する
`Navbar.tsx`同様、`App.tsx`からPropsを受け取りクリックイベントを設定しています。

```SideDrawer.tsx
    public render() {
        let drawerClasses = ['side-drawer'];

        if (this.props.show) {
            drawerClasses = ['side-drawer', 'open'];
        }

        return (
            <nav className={drawerClasses.join(' ')}>
                <div className="side-drawer__title-area">
                    <p className="side-drawer__title">Menu</p>
                </div>
                <ul>
                    <Link to="/about">
                        <li onClick={this.clickHandler}>About</li>
                    </Link>
                    <Link to="/works">
                        <li onClick={this.clickHandler}>Works</li>
                    </Link>
                    <Link to="/skills">
                        <li onClick={this.clickHandler}>Skills</li>
                    </Link>
                </ul>
            </nav>
        );
    }
```
`App.tsx`からサイドバー表示状態を受け取って、サイドバーのクラス定義を切り替えています。
切り替える理由は、サイドバーの表示アニメーションをCSSアニメーションで実装するためです。

```SideDrawer.css
.side-drawer {
    height: 100%;
    background: white;
    position: fixed;
    top: 0;
    left: 0;
    width: 70%;
    max-width: 300px;
    z-index: 200;
    transform: translateX(-100%);
    transition: transform 0.3s ease-out;
}

.side-drawer.open {
    box-shadow: 1px 0px 3px rgba(0, 0, 0, 0.5);
    transform: translateX(0);
}
```
具体的には、`z-index`で最前面に設定したサイドバーを`transform`と`transition`で左端から右へ移動させています。

### オーバーレイの実装
![overlay.PNG](https://qiita-image-store.s3.amazonaws.com/0/300336/ded5d910-1640-6b01-c708-9ba9f69117be.png)
この画像の右側にある、黒い半透明部分を実装します。

```App.tsx
  public render() {
    let backDrop;

    if (this.state.isOpen) {
      backDrop = <Backdrop backdropClickHandler={this.backdropClickHandler} />;
    }

    return (
      <div className="App">
        <Navbar drawToggleClickHandler={this.drawToggleClickHandler} />
        <SideDrawer show={this.state.isOpen} drawToggleClickHandler={this.drawToggleClickHandler} />
        {backDrop}
      </div>
    );
  }

  private backdropClickHandler = () => {
    this.setState({ isOpen: false });
  };
```
オーバーレイを構成するBackdropコンポーネントをサイドバーの表示状態に合わせて表示非表示を切り替えています。
オーバーレイ部分をタップするとサイドバーとオーバーレイを非表示にするため、クリックイベントを定義しています。
Backdropコンポーネントは以下のようになっています。

```Backdrop.tsx
class Backdrop extends React.Component<IProps, {}> {
    constructor(props: IProps) {
        super(props);
        this.clickHandler = this.clickHandler.bind(this);
    };

    public render() {
        return (
            <div className="backdrop" onClick={this.clickHandler}/>
        );
    }

    private clickHandler() {
        this.props.backdropClickHandler();
    }
}
```
今までと同様に、親コンポーネントから受け取ったPropsを基に初期化処理とクリックイベントの定義を行っています。
そして、CSSは以下のようになっています。

```Backdrop.css
.backdrop {
    position: fixed;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    background: rgba(0, 0, 0, 0.3);
    z-index: 100;
}
```
`z-index`でページとサイドバーの間に定義したオーバーレイを画面全体に展開しています。

## react-icons
ポートフォリオ内の三本線アイコン、Githubアイコンやtwitterアイコンは[React Icons](https://github.com/react-icons/react-icons)を使用しています。

### 導入方法
以下のコマンドで、パッケージをインストールします。

```
npm install react-icons --save
```

### 実装方法 
例：Github Octicons iconsのGithub Iconを選んだ場合

```Example.tsx
import { GoMarkGithub } from 'react-icons/go';

class Example extends React.Component {
    public render() {
        return (
            <GoMarkGithub />
        );
    }
}
```
1. [公式ドキュメント](https://react-icons.netlify.com/#/)から実装したいアイコンを選びます。
2. 選んだアイコン名と選んだアイコンを含んでいるモジュールを基に、アイコン一覧上部にあるインポート文をコンポーネントに挿入します。 
3. 選んだアイコンをコンポーネントとして挿入します。

アイコンの色やサイズを変更する場合は以下のようになります。
**ただし、React v16.3以上しか対応していません。**

```Example.tsx
import { IconContext } from "react-icons";
import { GoMarkGithub } from 'react-icons/go';

class Example extends React.Component {
    public render() {
        return (
            <IconContext.Provider value={{ color: "black", size: "3em" }}>
                <FaTwitterSquare />
            </IconContext.Provider>
        );
    }
}
```
アイコン用のインポート文に加えて`import { IconContext } from "react-icons";`を挿入し、アイコンコンポーネントを`IconContext.Provider`コンポーネントで包みます。
そして上記のように、`value={{}}`の`{{}}`内に変更内容を記入します。
`value={{}}`内に記入出来る内容は、[公式のREADME](https://github.com/react-icons/react-icons)を参照してください。

## react-router-dom
SPAでアプリを作成する際、アクセスしたURLによってどのページを開くかを制御するルーティングが必要があります。
Reactではルーティングを[react-router-dom](https://github.com/ReactTraining/react-router/tree/master/packages/react-router-dom)によって行います。

### 導入方法
以下のコマンドで、パッケージをインストールします。

```
npm install -S react-router-dom
```

### 実装方法
例を以下に示します。

```App.tsx
import * as React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

import './App.css';

import Navbar from './Components/Navbar/Navbar';
import About from './Pages/About/About';
import Home from './Pages/Home/Home';
import Skills from './Pages/Skills/Skills';
import Works from './Pages/Works/Works';

class App extends React.Component {
  public render() {
    return (
      <Router>
        <div className="App">
          <Navbar />
          <Switch>
            <Route path="/about" component={About} />
            <Route path="/works" component={Works} />
            <Route path="/skills" component={Skills} />
            <Route path="/" component={Home} />
            <Route component={Home} />
          </Switch>
        </div>
      </Router>
    );
  }
}

export default App;
```
ページ構成はTOPページとなるHomeと、About、Works、Skillsの４ページです。各々のページはコンポーネントとして作成されています。
`<Router>`タグと`<Route>`タグで、ページごとに作成したコンポーネントにルーティングを行っています。
ルーティングは`<Route>`タグを**降順**でパスチェックし、マッチしたパスのコンポーネントを表示します。
`<Switch>`タグを使用しない場合は降順でパスチェックし、マッチしたページを全て表示してしまうので注意が必要です。
加えて、パスチェックは**部分一致**で行われるので注意が必要です。
上記の例で言えば`<Route path="/" component={Home} />`を一番上に書いていたら、AboutなどのページへアクセスしてもTOPページが表示されてしまいます。
パスチェックを完全一致で行うようにさせるには、`exact={true}`を`<Route>`タグに記入します。

```App.tsx
<Route exact={true} path="/" component={Home} />
```

次は、各ページへのリンクを載せているナビゲーションバーを以下に示します。

```Navbar.tsx
import * as React from 'react';
import { Link } from "react-router-dom";

import './Navbar.css';

class Navbar extends React.Component {

    public render() {
        return (
            <header className="navbar" style={{ padding: 0 }}>
                <nav className="navbar__navigation">
                    <div>
                        <Link to="/MyPortfolio" className="navbar__title">Portfolio</Link>
                    </div>
                    <div className="spacer" style={{ flex: 1 }} />
                    <div className="navbar__navigation-items">
                        <ul>
                            <Link to="/about">
                                <li>about</li>
                            </Link>
                            <Link to="/works">
                                <li>Works</li>
                            </Link>
                            <Link to="/skills">
                                <li>Skills</li>
                            </Link>
                        </ul>
                    </div>
                </nav>
            </header>
        );
    }
}

export default Navbar;
```
`<Route>`タグで指定した各ページへのリンクは`<a>`タグではなく、`<Link>`タグを使用します。

## ReactでBootstrap 4を使用する
[ReactでBootstrap 4を使用する記事](https://qiita.com/eku0331/items/3c6b34aa40badd350a26)を見かけたので、記事に書かれていた、[reactstrap](https://reactstrap.github.io)を導入しました。

### 導入方法
まずは、Bootstrap 4とreactstrapをインストールします。

```
npm install --save bootstrap reactstrap
```
次に、reactstrapの型定義をインストールします。

```
npm install --save-dev @type/reactstrap
```
最後に、`index.tsx`に`bootstrap/dist/css/bootstrap.css`をインポートするインポート文を挿入します。

```index.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
import './index.css';
import registerServiceWorker from './registerServiceWorker';

import 'bootstrap/dist/css/bootstrap.css';

ReactDOM.render(
  <App />,
  document.getElementById('root') as HTMLElement
);
registerServiceWorker();
```

### 実装方法
今回は、[Card](https://reactstrap.github.io/components/card/)と[Layout](https://reactstrap.github.io/components/layout/)を使用しました。
使用した部分のソースを以下に示します。

```Skills.tsx
    public render() {
        return (
            <main className="main">
                <h1 className="skills-page__title">Skills</h1>
                <Container fluid={true} className="skills-page__container">
                    <Row>
                        <Col xs="12" md="4">
                            <Card className="skills-page__card">
                                <CardBody>
                                    <CardTitle>HTML &amp; CSS</CardTitle>
                                    <CardText>
                                        フロントエンドの制作で使用しています。
                                        このポートフォリオやOrgaSoundではBootstrap 4を使用しています。
                                        業務ではMaterial Design Liteを使用しています。
                                    </CardText>
                                </CardBody>
                            </Card>
                        </Col>
                        <Col xs="12" md="4">
                            <Card className="skills-page__card">
                                <CardBody>
                                    <CardTitle>SASS</CardTitle>
                                    <CardText>
                                        OrgaSoundの制作で使用しました。
                                        業務で使うかはわかりませんが、使えると便利であると感じたので学習中です。
                                    </CardText>
                                </CardBody>
                            </Card>
                        </Col>
                        <Col xs="12" md="4">
                            <Card className="skills-page__card">
                                <CardBody>
                                    <CardTitle>javascript (jQuery)</CardTitle>
                                    <CardText>
                                        業務で使用しています。
                                        主にES5以前の書式でjQueryと共に使用しています。
                                        恐らく2番目に長く使用しています。
                                    </CardText>
                                </CardBody>
                            </Card>
                        </Col>
                    </Row>
                </Container>
            </main>
        );
    }
```
`<Container fluid={true}>`で画面幅に合わせたコンテナを生成します。
生成したコンテナに対して`<Row>`タグを使用することで、コンテナを１２分割してレイアウトを制御出来るようになります。
`<Col>`タグで分割したレイアウトの配分を設定します。
画面幅によって、`xs`や`md`に書かれた値でレイアウトの配分を設定されます。
`xs`等については、[Bootstrapの公式ドキュメント](https://getbootstrap.com/docs/4.1/layout/grid/#grid-options)を参照してください。

Cardの部分に関しては、[公式のカードサンプル](https://reactstrap.github.io/components/card/)を基に使わない部分を削って作成しました。

## 完成
`npm start`でサーバを起動して、レイアウトや動作をチェックしたらいよいよ公開作業に入ります。

# 公開編
作成したポートフォリオは、[きっかけ](#%E3%81%8D%E3%81%A3%E3%81%8B%E3%81%91)に載せたポートフォリオを作成した２つの記事に書かれていたGitHub Pagesに公開することにしました。
[Netlify](https://www.netlify.com)も候補の１つでしたが、GitHub Pagesの方が簡単に公開出来ると判断したためGitHub Pagesを採用しました。
GitHub Pagesでの公開先をユーザーページ(`https://{username}.github.io/`)に設定しています。

## 前提
Github上にリポジトリを作成します。
ユーザーページを作成する際には、注意しなければならない点が２点あります。

- リポジトリ名は必ず**{username}.github.io**としてください。(`{username}`は自分のGithub ID)
- 公開ファイルは必ず**masterブランチ**に配置しなければならない。

そのため私はsourceブランチを開発ソース用、masterブランチを公開用に分けています。

## リモートのmasterブランチを消す
Github上でリポジトリを作成した際に生成されるリモートのmasterは、README.mdなど公開の際に不要なファイルが含まれているので消します。

### 開発ソースをsourceブランチにプッシュする
次の作業に必要なので、開発ソースをローカルで作ったsourceブランチからリモートのsourceブランチへプッシュします。

```
git checkout -b source
git push origin source
```

### Default branchをsourceブランチに変更する
Githubのリポジトリを開いて、`Settings`から`Branches`を開きます。
![BranchesSettings.PNG](https://qiita-image-store.s3.amazonaws.com/0/300336/22646694-a8de-86bc-36a5-ca247fdbfdc8.png)
画像のように、Default branchをsourceブランチに変更します。

### リモートのmasterブランチを削除する
以下のコマンドで、リモートのmasterブランチを削除します。

```
git push -f --delete origin master
```

## gh-pagesをインストールする
以下のコマンドで、[gh-pages](https://github.com/tschaub/gh-pages)をインストールします。

```
npm install gh-pages --save-dev
```
gh-pagesは、GitHub Pagesに簡単にデプロイすることが出来るパッケージです。

## package.jsonに公開先のURLを指定する
以下の一行を`package.json`に挿入します。

```package.json
"homepage": "https://{username}.github.io",
```
`{username}`は自分のGithub IDを入力してください。

## package.jsonに「predeploy」「deploy」コマンドを追加
`package.json`の`scripts`に以下の２行を挿入します。

```package.json
    "predeploy": "npm run build",
    "deploy": "gh-pages -d build -b master",
```
`predeploy`コマンドはコンパイルを実行して、公開ファイルを生成します。デフォルトではbuildフォルダに生成されます。
`deploy`コマンドは`-d`で指定したディレクトリを、`-b`で指定したブランチにプッシュします。
上記では`-d`で公開ファイルが格納されているbuildフォルダを、`-b`で公開対象のmasterブランチを指定しています。

## デプロイする
以下のコマンドで、デプロイを実行します。

```
npm run deploy
```
デプロイに成功すると、Githubのリポジトリ上にmasterブランチが生成されています。

## 公開完了
`package.json`の`homepage`に指定したURLにアクセスすると、作成したページが表示されます。
表示されない場合は、数分後にもう一度アクセスすると表示されると思います。

# 今後やりたいこと
- CSSで作ったのでSASSにしたい  
PostCSSも候補の１つでしたが、個別に必要なパッケージをインストールするのは手間がかかると感じたのでSASSにしました。
- ナビゲーションバーをreactstrapで作り直したい  
今回は[チュートリアル動画](https://www.youtube.com/watch?v=l6nmysZKHFU)の通りに自作しましたが、reactstrapでナビゲーションバーを作成出来ることに自作後に気付きました。
- ~~Steam APIでポートフォリオにSteamで所有しているゲーム一覧を載せたい~~  
Web APIを活用してみたいと考えて私にとっては身近なSteamに目を付けたが、ポートフォリオに載せるものか迷ったので不採用としました。

# 感想
ポートフォリオを作成するのに約３日、この記事を書くのに約３日、とにかく大変でした。
しかし自分が作りたいものを作った後は、とても大きな達成感を得られました。
Reactに対する知見も得られて、苦労した甲斐がありました。

# まとめ
参考資料は少ないですがReactで開発する際にTypescriptを使うと捗ると感じたので、この記事が少しでも皆さんのお役に立てば幸いです。