Reactで簡易コーポレートサイトを作成する #1 -Top/Contactコンポーネント編-

# 概要
webSiteをReactで作成します。
Reactの基本構造を理解し、Topページ・お問合せページのコンポーネントを作成します。

# 完成イメージ
<img width="1686" alt="000001.jpg" src="https://dl.dropboxusercontent.com/s/vq8fw4q4d7sdgn2/000001.jpg">



# プロジェクト作成
まず、プロジェクトを作成します。
作業フォルダを設置したい場所にコンソールで移動し下記コマンドを実行します。
react-websiteという名前のプロジェクトを作成しました。

```
npx create-react-app react-website
```

完了すると、プロジェクト名で作業フォルダができています。
フォルダに移動し、一旦開発サーバを起動してみます。

```
cd react-website
npm start
```
ローディングが完了すると自動的にブラウザが立ち上がりwebサイトが表示されます。
<img width="1711" alt="000010.jpg" src="https://dl.dropboxusercontent.com/s/satbt0w1z7daado/000010.jpg">


## 編集する
VisualStudioCodeでプロジェクトフォルダを開きボイラープレートを編集して不要な部分を削除していきます。

App.js ファイルはwebサイトのルートになります。
一旦` <div className="App">`内を削除してHOMEと表示させてみます。 logo.svg も利用しないのでimportを削除します。

```src/App.js
import './App.css';

function App() {
  return (
    <div className="App">
      <h1>Home</h1>
    </div>
  );
}

export default App;
```
変更を加えて保存するとすぐに反映されます（npm startしたままの状態の場合）。
<img width="1711" alt="000020.jpg" src="https://dl.dropboxusercontent.com/s/sdgxuyed23cntyt/000020.jpg">


# TOP画面の作成
## Top.js
TOP画面を作成します。
整理するためsrcフォルダの中にscreensというフォルダを作ります。
screenフォルダ内にTop.jsを作成します。

```
mkdir src/screens
touch src/screens/Top.js
```
top.jsに記述します。
これはReactコンポーネントの基本的な構造です。
Reactでは、どこでもコンポーネントをimportすることができます。


```Top.js
import React from "react";

const Top = () => {
    return (

    )
}

export default Top;
```
TOP画面に中身を追加します。
中身は[簡易コーポレートサイトを作成する](https://qiita.com/minimumskills/private/0a41bb64480c88505c3b)で作成したwebsiteのindex.htmlの中からコピーして作成します。
コピーするのは`<header>〜</main>`です。
Reactでは一つのコンポーネントに複数の要素は入れられないので、フラグメント（`<> </>`）で囲んで一つの要素にまとめます。
コピーして、top.jsのreturn ()内に貼り付けます。
textareaのrowsはHTMLとは異なり`{}`で囲んで数値を指定します。

```diff_javascript:Top.js
    import React from "react";

    const Top = () => {
        return (
+           <>
+               <header class="top">
+                   <h1 class="top_msg">bluecode, Lifestyle developer.</h1>
+               </header>
+               <main>
+                   <section class="content">
+                       <h2>websiteの最新情報</h2>
+                       <p>最新の情報をご案内します。</p>
+                   </section>
+               </main>
+           </>
        )
    }

    export default Top;
```

```javascript:コピペ用
<>
    <header class="top">
        <h1 class="top_msg">bluecode, Lifestyle developer.</h1>
    </header>
    <main>
        <section class="content">
            <h2>websiteの最新情報</h2>
            <p>最新の情報をご案内します。</p>
        </section>
    </main>
</>
```

## App.js
TOP画面を見えるようにするためには、App.jsにTOP.jsをインポートする必要があります。
そして、それをHTMLタグのように設定してレンダリングすることができます。

```diff_javascript:App.js
  import './App.css';

+ import Top from './screens/Top';

  function App() {
    return (
      <div className="App">
-       <h1>Home</h1>
+       <Top />
      </div>
    );
  }

  export default App;
```
保存してブラウザを確認してみます。
スタイルが設定されていないので崩れていますが、コンテンツは表示できていることが確認できます。<img width="1711" alt="000030.jpg" src="https://dl.dropboxusercontent.com/s/muya19niqeicqra/000030.jpg">


## App.css
スタイルを設定して確認してみます。
基本的にApp.cssに追加すれば適用されますが（App.jsで読み込んでいるため）、各コンポーネントで使うものについては分割してそれぞれコンポーネントで読み込むように記述していきます。
App.cssにはすべてのコンポーネントで共通するものを追加します。
一度App.cssの中身をすべて削除して必要なものを[最終的なコードのstyle.css](https://qiita.com/minimumskills/private/5bb8ce1c4236f14d882b#%E6%9C%80%E7%B5%82%E7%9A%84%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89)から貼り付けます。
また、Reactでは、テンプレートですでに設定されているrootと表示する全体をまとめるAppというクラスがあるためこの２つについても高さを100%に指定しておきます（フッターが下に表示されるようにするため）

```App.css
html {
  height: 100%;
}

#root {
  height: 100%;
}

.App {
  height: 100%;
}

body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  height: 100%;
}
```
## Top.css
次にTop.js用のcssを作成してみます。

```
mkdir src/screens/styles
touch src/screens/styles/Top.css
```

```src/screens/styles/Top.css
.top {
    /* 背景に取得した画像を設定 */
    background-image: url("https://picsum.photos/1000/300");
    /* 画像をいっぱいに表示 */
    background-size: cover;
    /* 表示する高さを画面の40％に */
    height: 40vh;
    /* 表示幅を画面の90%に */
    width: 100%;
    /* フレックスボックスを指定*/
    display: flex;
    /* フレックスアイテムを使って両端から中央に配置*/
    justify-content: center;
    /* フレックスアイテムを使って上下から中央に配置 */
    align-items: center;
    /* テキストの配置を中央揃えに */
    text-align: center;
}

.top_msg {
    /* 文字色を白に */
    color: #fff;
}

.content {
    width: 90%;
    margin: 0 auto;
    text-align: center;
}
```

## Top.js
Top.cssをインポートします。
Reactではクラス名はclassNameとなるので`class="xxx"`と記述している部分をすべて`className="xxx"`の形式に変更します。

```diff_javascript:Top.js
    import React from "react";
+   import './styles/Top.css';

    const Top = () => {
        return (
            <>
-               <header class="top">
+               <header className="top">
-                   <h1 class="top_msg">bluecode, Lifestyle developer.</h1>
+                   <h1 className="top_msg">bluecode, Lifestyle developer.</h1>
                </header>
                <main>
-                   <section class="content">
+                   <section className="content">   
                        <h2>websiteの最新情報</h2>
                        <p>最新の情報をご案内します。</p>
                    </section>
                </main>
            </>
        )
    }

    export default Top;
```

```javascript:コピペ用
<>
    <header className="top">
        <h1 className="top_msg">bluecode, Lifestyle developer.</h1>
    </header>
    <main>
        <section className="content">
            <h2>websiteの最新情報</h2>
            <p>最新の情報をご案内します。</p>
        </section>
    </main>
</>
```
保存して確認します。
<img width="1711" alt="000040.jpg" src="https://dl.dropboxusercontent.com/s/ujvpxoew31o1upx/000040.jpg">


# 問合せ画面の作成
作成していきます。
必要となるファイルを作成していきます。
screens内にContact.js、stylesにContact.cssを作成します。

```
touch src/screens/Contact.js src/screens/styles/Contact.css
```

## Contact.js
基本構造を記述します。

```Contact.js
import React from "react";

const Contact = () => {
    return (

    )
}
export default Contact;
```
Top.js同様にフロントエンド開発の最終的なコードのContact.htmlから`<main>〜</main>`をコピーして貼り付けます。
このとき、問合せ内容のtextareaで行を指定している`rows=4`について、記述が`rows={4}`となるので変更しておきます。

```diff_javascript:Contact.js
    import React from "react";

    const Contact = () => {
        return (
+           <main class="contact_form">
+               <h2>お問合せ</h2>
+               <form>
+                   <div class="form_group">
+                       <label>お名前</label>
+                       <input type="text" id="name" />
+                       <span class="form_error hidden" id="name_error">お名前は必須です。</span>
+                   </div>
+                   <div class="form_group">
+                       <label>email</label>
+                       <input type="email" id="email" />
+                       <span class="form_error hidden" id="email_error">emailは必須かつemailの形式で入力してください。</span>
+                   </div>
+                   <div class="form_group">
+                       <label>お問合せ内容</label>
+                       <textarea id="body" rows={4}></textarea>
+                       <span class="form_error hidden" id="body_error">お問合せ内容は必須かつ1文字以上10文字以下で入力してください。</span>
+                   </div>
+                   <button class="submit_btn" id="submit_btn">送信</button>
+               </form>
+           </main >
        )
    }
    export default Contact;
```

```javascript:コピペ用
<main class="contact_form">
    <h2>お問合せ</h2>
    <form>
        <div class="form_group">
            <label>お名前</label>
            <input type="text" id="name" />
            <span class="form_error hidden" id="name_error">お名前は必須です。</span>
        </div>
        <div class="form_group">
            <label>email</label>
            <input type="email" id="email" />
            <span class="form_error hidden" id="email_error">emailは必須かつemailの形式で入力してください。</span>
        </div>
        <div class="form_group">
            <label>お問合せ内容</label>
            <textarea id="body" rows={4}></textarea>
            <span class="form_error hidden" id="body_error">お問合せ内容は必須かつ1文字以上10文字以下で入力してください。</span>
        </div>
        <button class="submit_btn" id="submit_btn">送信</button>
    </form>
</main >
```

## App.js
App.jsでインポートします。

```diff_javascript:App.js
    import './App.css';
    import Top from './screens/Top';
+   import Contact from './screens/Contact';

    function App() {
      return (
        <div className="App">
          <Top />
+         <Contact />
        </div>
      );
    }

    export default App;
```

## Contact.css
Contactコンポーネントで使っているものについてcssを記述します。
エラー文言の表示はcssで制御しなくなるため、.hiddenは不要になるので一旦cssからも削除しておきます。

```Contact.css
.contact_form {
    padding: 40px 20px;
    text-align: center;
}

.form_group {
    border-top: 1px solid #ddd;
    margin-top: 20px;
    padding: 20px 0px;
    width: 100%;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
}

.form_group label {
    width: 30%;
    font-weight: bold;
    font-size: 18px;
}

.form_group input,
.form_group textarea {
    border: 1px solid #ddd;
    border-radius: 6px;
    width: 60%;
    font-size: 18px;
}

.form_group input {
    height: 40px;
}

.submit_btn {
    padding: 5px 15px;
    background-color: #049dbf;
    color: #fff;
    border-radius: 5px;
    border: 0;
    font-size: 16px;
}

.submit_btn:hover {
    background-color: #0183a0;
}

.form_error {
    padding-left: 30%;
    width: 60%;
    font-size: small;
    color: red;
    text-align: start;
    padding-top: 10px;
}

/*スマホ対応*/
@media screen and (max-width: 640px) {
    /* お問合せフォーム */
    .form_group label {
        width: 100%;
        padding-bottom: 10px;
    }

    .form_group input,
    .form_group textarea {
        width: 100%;
        margin: 0;
        padding: 0;
    }

    .submit_btn {
        width: 100%;
        height: 50px;
    }

    .form_error {
        width: 100%;
        text-align: left;
        padding: 5px 0;
    }
}
```

## Contac.js
Contact.cssをインポートして、`class`を`className`に変更します。

```Contact.js
import React from "react";
import './styles/Contact.css'; 

const Contact = () => {
    return (
        <main className="contact_form">
            <h2>お問合せ</h2>
            <form>
                <div className="form_group">
                    <label>お名前</label>
                    <input type="text" id="name" />
                    <span className="form_error hidden" id="name_error">お名前は必須です。</span>
                </div>
                <div className="form_group">
                    <label>email</label>
                    <input type="email" id="email" />
                    <span className="form_error hidden" id="email_error">emailは必須かつemailの形式で入力してください。</span>
                </div>
                <div className="form_group">
                    <label>お問合せ内容</label>
                    <textarea id="body" rows={4}></textarea>
                    <span className="form_error hidden" id="body_error">お問合せ内容は必須かつ1文字以上10文字以下で入力してください。</span>
                </div>
                <button className="submit_btn" id="submit_btn">送信</button>
            </form>
        </main >
    )
}
export default Contact;
```
保存して確認します。
TOP画面をスクロールすると、下にお問い合わせができています。
<img width="1686" alt="000050.jpg" src="https://dl.dropboxusercontent.com/s/n3rtd9yxs05zp25/000050.jpg">

これで、Topページとお問合せページのコンポーネントは完成です。

# 最終的なコード

## App.js

```App.js
import './App.css';
import Top from './screens/Top';
import Contact from './screens/Contact';

function App() {
  return (
    <div className="App">
      <Top />
      <Contact />
    </div>
  );
}

export default App;
```

## Top.css

```Top.css
.top {
    /* 背景に取得した画像を設定 */
    background-image: url("https://picsum.photos/1000/300");
    /* 画像をいっぱいに表示 */
    background-size: cover;
    /* 表示する高さを画面の40％に */
    height: 40vh;
    /* 表示幅を画面の90%に */
    width: 100%;
    /* フレックスボックスを指定*/
    display: flex;
    /* フレックスアイテムを使って両端から中央に配置*/
    justify-content: center;
    /* フレックスアイテムを使って上下から中央に配置 */
    align-items: center;
    /* テキストの配置を中央揃えに */
    text-align: center;
}

.top_msg {
    /* 文字色を白に */
    color: #fff;
}

.content {
    width: 90%;
    margin: 0 auto;
    text-align: center;
}
```
## Contact.css

```Contact.css
.contact_form {
    padding: 40px 20px;
    text-align: center;
}

.form_group {
    border-top: 1px solid #ddd;
    margin-top: 20px;
    padding: 20px 0px;
    width: 100%;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
}

.form_group label {
    width: 30%;
    font-weight: bold;
    font-size: 18px;
}

.form_group input,
.form_group textarea {
    border: 1px solid #ddd;
    border-radius: 6px;
    width: 60%;
    font-size: 18px;
}

.form_group input {
    height: 40px;
}

.submit_btn {
    padding: 5px 15px;
    background-color: #049dbf;
    color: #fff;
    border-radius: 5px;
    border: 0;
    font-size: 16px;
}

.submit_btn:hover {
    background-color: #0183a0;
}

.form_error {
    padding-left: 30%;
    width: 60%;
    font-size: small;
    color: red;
    text-align: start;
    padding-top: 10px;
}

/*スマホ対応*/
@media screen and (max-width: 640px) {

    /* お問合せフォーム */
    .form_group label {
        width: 100%;
        padding-bottom: 10px;
    }

    .form_group input,
    .form_group textarea {
        width: 100%;
        margin: 0;
        padding: 0;
    }

    .submit_btn {
        width: 100%;
        height: 50px;
    }

    .form_error {
        width: 100%;
        text-align: left;
        padding: 5px 0;
    }
}
```
## Top.js
```Top.js
import React from "react";
import './styles/Top.css';


const Top = () => {
    return (
        <>
            <header className="top">
                <h1 className="top_msg">bluecode, Lifestyle developer.</h1>
            </header>
            <main>
                <section className="content">
                    <h2>websiteの最新情報</h2>
                    <p>最新の情報をご案内します。</p>
                </section>
            </main>
        </>
    )
}

export default Top;
```

## Contact.js
```Contact.js
import React from "react";
import './styles/Contact.css';

const Contact = () => {
    return (
        <main className="contact_form">
            <h2>お問合せ</h2>
            <form>
                <div className="form_group">
                    <label>お名前</label>
                    <input type="text" id="name" />
                    <span className="form_error hidden" id="name_error">お名前は必須です。</span>
                </div>
                <div className="form_group">
                    <label>email</label>
                    <input type="email" id="email" />
                    <span className="form_error hidden" id="email_error">emailは必須かつemailの形式で入力してください。</span>
                </div>
                <div className="form_group">
                    <label>お問合せ内容</label>
                    <textarea id="body" rows={4}></textarea>
                    <span className="form_error hidden" id="body_error">お問合せ内容は必須かつ1文字以上10文字以下で入力してください。</span>
                </div>
                <button className="submit_btn" id="submit_btn">送信</button>
            </form>
        </main >
    )
}
export default Contact;
```

# 関連コンテンツ
- 次：[Reactで簡易コーポレートサイトを作成する #2 -ナビゲーションバーとフッター編-](https://qiita.com/minimumskills/private/196cd269af311b06358c)