Reactの身内向けチュートリアル（その２）


Vue.全盛の中、社内メンバー向けのReactの簡単なチュートリアル。

## シリーズ

* [その１：create-react-appの簡単な使い方とファイル構成](https://qiita.com/zaburo/private/99dc965d273f1922deae)
* [その２：簡単なページの作成（共通パーツ化含む）とreact-routernによるルーティング](https://qiita.com/zaburo/private/07182451cc346071b358)（この記事）
* [その３：簡易認証機能（ログイン・ログアウト）の追加](https://qiita.com/zaburo/private/69fb5352158a9c281aa8)

## その２の概要

* Reactでトップナビゲーションのある普通のページを作る方法の習得
* HeaderやFooter等の共通部分をパーツ化する方法の習得


## 最低限のレイアウトをしてみる

App.jsをいじってそれっぽいレイアウトにしてみます。

>なお、デフォルトで生成されるコードは関数コンポーネントですが、Redux等を利用することを想定しclassコンポーネントに変更しています。

### App.js

```js:App.js
import React from 'react';

class App extends React.Component {
     render() {
          return (
               <div>
                    <nav style={{ background: "#666" }}>
                         <ul style={{ display: 'flex', listStyle: 'none' }}>
                              <li style={{ margin: 10 }}><a href="/" style={{ color: "#fff", textDecoration: 'none' }}>Home</a></li>
                              <li style={{ margin: 10 }}><a href="/about" style={{ color: "#fff", textDecoration: 'none' }}>About</a></li>
                         </ul>
                    </nav>

                    <header style={{ height: 200, background: "#ddd" }}>
                         header
               </header>

                    <div id="main" style={{ height: 300, background: "#eee" }}>
                         main
               </div>

                    <footer style={{ height: 100, background: "#666", color: "#fff" }}>
                         footer
               </footer>
               </div>
          );
     }
}

export default App;
```

動作確認してみます。

```bash
yarn start
```

下記のような画面が表示されればOKです。

![スクリーンショット 2019-11-14 12.00.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/2f0ff897-7ac5-e223-ee6b-9fb127639569.png "スクリーンショット 2019-11-14 12.00.37.png")


## ルーティング（ページ移動）の設定

ナビゲーションをクリックしても何も起こりません。それぞれHomeやAbout画面が表示されるようにしていきます。
ただ、create-react-appで作成できるアプリ？は基本SPA（Single Page Application）であるため、ページは1ページしかありません。なので通常のHTMLによるWeb作成と異なり、ルーティングという手法でページ移動を行います（ページはあくまで１ページで、移動しているように見せる）。

まず、ルーティングのためのライブラリをインストールします。react-routerというものが事実上の標準となっています。


```bash
yarn add react-router-dom
```

では、Home、Aboutそれぞれのページを作成してみます。
ここではApp.jsと同階層にscreensフォルダを作成し、その中にページ毎にHome.js, About.jsを作成していくようにしてみます。

ページの内容は上記で作成したApp.jsをベースに、クラス名や表示内容の一部を変更してみます。


### screens/Home.js


まずはHome.js。

```diff:Home.js
import React from 'react';

+class Home extends React.Component {
     render() {
          return (
               <div>
                    <nav style={{ background: "#666" }}>
                         <ul style={{ display: 'flex', listStyle: 'none' }}>
                              <li style={{ margin: 10 }}><a href="/" style={{ color: "#fff", textDecoration: 'none' }}>Home</a></li>
                              <li style={{ margin: 10 }}><a href="/about" style={{ color: "#fff", textDecoration: 'none' }}>About</a></li>
                         </ul>
                    </nav>

                    <header style={{ height: 200, background: "#ddd" }}>
                         header
               </header>

                    <div id="main" style={{ height: 300, background: "#eee" }}>
+                         main（Home）
               </div>

                    <footer style={{ height: 100, background: "#666", color: "#fff" }}>
                         footer
               </footer>
               </div>
          );
     }
}

+export default Home;
```

### screens/About.js

そして、About.js。

```diff:About.js
import React from 'react';

+class About extends React.Component {
     render() {
          return (
               <div>
                    <nav style={{ background: "#666" }}>
                         <ul style={{ display: 'flex', listStyle: 'none' }}>
                              <li style={{ margin: 10 }}><a href="/" style={{ color: "#fff", textDecoration: 'none' }}>Home</a></li>
                              <li style={{ margin: 10 }}><a href="/about" style={{ color: "#fff", textDecoration: 'none' }}>About</a></li>
                         </ul>
                    </nav>

                    <header style={{ height: 200, background: "#ddd" }}>
                         header
               </header>

                    <div id="main" style={{ height: 300, background: "#eee" }}>
+                         main（About）
               </div>

                    <footer style={{ height: 100, background: "#666", color: "#fff" }}>
                         footer
               </footer>
               </div>
          );
     }
}

+export default About;
```

### App.js

Home.js, About.jsが準備できたら、App.jsの内容を変更しルーティングできるよう設定を行います。
各ページを読込、pathとページ（コンポーネント）をマッピングさせます。まあ、意味はわかると思います。

```js:App.js
import React from 'react';
import { BrowserRouter, Route, Switch, NavLink } from 'react-router-dom';

//import screens
import Home from './screens/Home';
import About from './screens/About';

class App extends React.Component {
     render() {
          return (
               <BrowserRouter>
                    <Switch>
                         <Route exact path="/" component={Home} />
                         <Route exact path="/about" component={About} />
                         <Route render={() => (<p>Page not found.</p>)} />
                    </Switch>
               </BrowserRouter>
          );
     }
}

export default App;
```

### 動作確認する

yarn startさせ、動作を確認してください。

```bash
yarn start
```

Home, AboutをクリックするとURLおよびコンテンツ内容が変化しているはずです。
下記画面ではAboutボタンを押したら、コンテンツもAboutになっている。

![スクリーンショット 2019-11-14 12.16.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/2c1ca9cf-d12f-53d8-3e2d-50a547be7c23.png "スクリーンショット 2019-11-14 12.16.00.png")


## 共通部品化する

上記の例ではHome.js, About.jsに重複したコードが書かれており非常に冗長です。Nav, Header, Footer等は共通化したいので、それを行います。
共通化のためには各部を切り出して個別のコンポーネントに（部品化）します。
screensの中に、各部を担うjsを作成していきます。

### Nav.js（ナビゲーション部）

```js:Nav.js
import React from 'react';

class Nav extends React.Component {
    render() {
        return (
            <nav style={{ background: "#666" }}>
                <ul style={{ display: 'flex', listStyle: 'none' }}>
                    <li style={{ margin: 10 }}><a href="/" style={{ color: "#fff", textDecoration: 'none' }}>Home</a></li>
                    <li style={{ margin: 10 }}><a href="/about" style={{ color: "#fff", textDecoration: 'none' }}>About</a></li>
                </ul>
            </nav>
        );
    }
}

export default Nav;
```

### Header.js（ヘッダー部）

```js:Header.js
import React from 'react';

class Header extends React.Component {
    render() {
        return (
            <header style={{ height: 200, background: "#ddd" }}>
                header
            </header>
        );
    }
}

export default Header;
```

### HomeContent.js（Homeのコンテンツ部）

```js:HomeContent.js
import React from 'react';

class HomeContent extends React.Component {
    render() {
        return (
            <div id="main" style={{ height: 300, background: "#eee" }}>
                HomeContent
            </div>

        );
    }
}

export default HomeContent;
```

### AboutContent.js（Aboutのコンテンツ部）

```js:AboutContent.js
import React from 'react';

class AboutContent extends React.Component {
    render() {
        return (
            <div id="main" style={{ height: 300, background: "#eee" }}>
                AboutContent
            </div>

        );
    }
}

export default AboutContent;
```

### Footer.js（フッター部）
```js:Footer.js
import React from 'react';

class Footer extends React.Component {
    render() {
        return (
            <footer style={{ height: 100, background: "#666", color: "#fff" }}>
                footer
            </footer>
        );
    }
}

export default Footer;
```

ここまでで各部のコンポーネント化が完了しました。ここからはHome.jsとAbout.jsを各パーツを利用するように変更します。

### Home

まずはHome.jsの変更。

```js:Home.js
import React from 'react';

//screens
import Nav from './Nav';
import Header from './Header';
import HomeContent from './HomeContent';
import Footer from './Footer';

class Home extends React.Component {
    render() {
        return (
            <React.Fragment>
                <Nav />
                <Header />
                <HomeContent />
                <Footer />
            </React.Fragment>
        );
    }
}

export default Home;
```

### About

ほぼ同じですが、About.jsの変更。違いはコンテンツ部だけです。

```js:About.js
import React from 'react';

//screens
import Nav from './Nav';
import Header from './Header';
import AboutContent from './AboutContent';
import Footer from './Footer';

class About extends React.Component {
    render() {
        return (
            <React.Fragment>
                <Nav />
                <Header />
                <AboutContent />
                <Footer />
            </React.Fragment>
        );
    }
}

export default About;
```

### 動作確認

yarn startさせ、動作を確認します。変更はレウアウトだけなので動作に変化は無いはずです。

## Navを少し改良する

動作に問題はありませんんが、HomeにいるのかAboutにいるのかわかりにくいので、Navの文字色を変更してみます。
NavLinkを利用すれば、active時のクラスやスタイルを指定、変更することができるので利用してみます。

```js:Nav.js
import React from 'react';
import { NavLink } from 'react-router-dom';

class Nav extends React.Component {
    render() {
        return (
            <nav style={{ background: "#666" }}>
                <ul style={{ display: 'flex', listStyle: 'none' }}>
                    <li style={{ margin: 10 }}><NavLink exact to="/" style={{ color: "#fff", textDecoration: 'none' }} activeStyle={{ color: '#aaf' }}>Home</NavLink></li>
                    <li style={{ margin: 10 }}><NavLink exact to="/about" style={{ color: "#fff", textDecoration: 'none' }} activeStyle={{ color: '#aaf' }}>About</NavLink></li>
                </ul>
            </nav>
        );
    }
}

export default Nav;
```

これにより、各ページにいるときのスタイルを変更できます。

![スクリーンショット 2019-11-14 12.32.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/85b2faf6-0f42-e5d6-22c9-3df2accb9557.png "スクリーンショット 2019-11-14 12.32.08.png")



## その２のおさらい

* Reactで作成したSPAにてルーティングさせる方法がわかりました。
* 共通部をパーツ化する方法がわかりました。


以上です。その３につづく。