【旧情報】 作ったWebサイトにフォームくらいは欲しいよねって時。

# 2020-02-19追記

現時点ではGoogleForm側の仕様変更により、下記手順では出来なくなっています。

そもそもGoogleが推奨しているやり方ではない（と私は認識しています）ので、告知なく仕様の変更が行われ、機能しなくなる恐れがあります。
Googleの推奨する、GoogleAPIを利用したSpreadSheetへのレコード追加や、NetlifyFormなど、その他の手段を利用してフォームを作ることをオススメいたします！

# やりたいこと
コーポレートやLPなどの案件の時、たまにこういう時あります。
> Next.js & Nowや、Nuxt.js & Netlifyなどの構成で、サーバーレスで構築してね
> あ、でもなんらかの形でFormは作ってね！

うーん、なんか簡単にできないかな
色々実現方法はあると思います

- [Netlify Form](https://docs.netlify.com/forms/setup/)
    - Netlify利用ならあっという間にできます。
    - [こちらの記事](https://qiita.com/NaokiIshimura/items/bce2f0b865ec1bc16a53)にめっちゃ詳しく乗ってます。今回は取り扱いません。
- [GoogleForm](https://www.google.com/intl/ja_jp/forms/about/)
    - 単純にリンク貼るだけでも、機能としては必要十分ですね。

>  「ただちょっとコーポレートとかで使うには、`ザ GoogleForm`って見た目がねえ。。」

:thinking_face:

# やったこと
**フォーム機能はGoogleFormに乗っかりつつ、フロントは作ってPOSTで通信する**

## はじめに
TypeScriptを一部入れてます。実際は`.tsx`です。Snippetが対応していないのか赤線出てるので`.jsx`にしてます。

## 1. GoogleFormの用意
普通にGoogleFormを使ってフォームを作りましょう。
![問い合わせフォーム_-_Google_フォーム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317515/a81e17ed-0901-e39b-299f-6180c82ea11f.png)

## 2. POST通信に必要なパラメーターを確認
- プレビューを利用して、実際のフォーム入力画面を表示しましょう。
![問い合わせフォーム_-_Google_フォーム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317515/158095de-b712-d3ad-debf-17c0fa2c3989.png)

- DevelomentToolsなどでソースを表示し、各フォームの値がどのようなparamでやりとりしているか確認しましょう。
    - 今回は、GoogleChromeにて`⌘ + Shift + C`などで開けるDevelimentToolsで説明します。
![問い合わせフォーム_と_コンタクトページの追加_by_wataboru_·_Pull_Request__10_·_mediful_corporate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317515/5be449c6-3454-f1d8-b673-fd7c47b0a55d.png)

- ラジオボタンなど`hidden`で見つけにくい物は、ソース検索で`entry`と入力して探しましょう！
![問い合わせフォーム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317515/31afe47d-fa24-cef3-fbfc-da4ef8a84a5a.png)

- 最後に、ActionURLを探しましょう。`<form`とか検索すれば見つけられます。
![問い合わせフォーム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317515/42d1fada-833c-b2ba-1272-c32faae5513b.png)

## 3. 集めた情報をソースにまとめておく

オブジェクトとして、一つのファイル（`.js`や`.tsx`など)にまとめておきしょう。

```constants/ContactGoogleForm.tsx
export const ContactGoogleForm = {
  action:
    'https://docs.google.com/forms/u/0/d/e/1FAIpQLSdCgDgog4LTBHSwuSliZwa9Q7mEt7dSZypREwDEJXVFmQvOvg/formResponse',
  name: 'entry.1902046290',
  gender: 'entry.1524608684',
  inquiry: 'entry.1741685192',
}
```

## 4. フロントコーディング
ここは楽しいところですね。いい感じに仕上げましょう必要ならUIフレームワークなども利用しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317515/3bf60738-b532-ed82-2065-a8c41b0ae2cb.png)

```components/ContactForm/index.jsx
import React from 'react'
import styled from 'styled-components'

const StyledTable = styled.table`
  width: 100%;
  table-layout: fixed;
`

const TextArea = styled.textarea`
  margin-top: 10px;
  width: 100%;
  height: 100px;
`

const Th = styled.th`
  padding-top: 10px;
`

const StyledSubmit = styled.button`
  border: 1px solid #000;
  display: block;
  padding: 18px 90px;
  font-size: 16px;
  margin: 10px auto 0;
  color: #000;
`

const StyledInput = styled.input`
  width: 100%;
  border: solid 1px #000;
  padding: 4px;
  box-sizing: border-box;
  font-size: 16px;
`

const options: string[] = ['男性', '女性', '回答しない']

export const ContactForm: React.FC<any> = () => {
  return (
    <form>
      <StyledTable>
        <tbody>
          <tr>
            <Th>
              <p>お名前</p>
            </Th>
            <td>
              <StyledInput type={'text'} name={'name'} />
            </td>
          </tr>
          <tr>
            <Th>
              <p>性別</p>
            </Th>
            <td>
              {options.map((option) => (
                <div key={option}>
                  <label>
                    <input type={'radio'} name={'gender'} value={option} />
                    {option}
                  </label>
                </div>
              ))}
            </td>
          </tr>
        </tbody>
      </StyledTable>
      <p>お問い合わせ内容</p>
      <TextArea name={'inquiry'} />
      <StyledSubmit type={'submit'}>送信する</StyledSubmit>
    </form>
  )
}

```

## 5. データ連携（ReactHookForm利用）

今回は、超簡単にFormを生成できる[ReactHookForm](https://react-hook-form.com/)を利用しました。
色々と便利に利用できますが、今回は以下の通り最低限利用しました。

- Formの`onSubmit`に`handleSubmit`と関数を渡す
- 各Inputに`ref={register()}`を追加

```components/ContactForm/index.jsx
import React from 'react'
import styled from 'styled-components'

// react-hook-form
import { useForm, Controller } from 'react-hook-form'

// 先ほど取得したGoogleForm関連データ
import { ContactGoogleForm } from '@/constants/ContactGoogleForm'

// axios
import axios from 'axios'

// ~~~ 中略 ~~~

export const ContactForm: React.FC<any> = () => {
  const { register, handleSubmit } = useForm({
    mode: 'onChange',
  })
  return (
    <>
      <form noValidate onSubmit={handleSubmit(submit)}>
        <StyledTable>
          <tbody>
            <tr>
              <Th>
                <p>お名前</p>
              </Th>
              <td>
                <StyledInput type={'text'} name={'name'} ref={register()} />
              </td>
            </tr>
            <tr>
              <Th>
                <p>性別</p>
              </Th>
              <td>
                {options.map((option) => (
                  <div key={option}>
                    <label>
                      <input
                        type={'radio'}
                        name={'gender'}
                        value={option}
                        ref={register()}
                      />
                      {option}
                    </label>
                  </div>
                ))}
              </td>
            </tr>
          </tbody>
        </StyledTable>
        <p>お問い合わせ内容</p>
        <TextArea name={'inquiry'} ref={register()} />
        <StyledSubmit type={'submit'}>送信する</StyledSubmit>
      </form>
    </>
  )
}


const submit = (values) => {
console.log(values)
}
```


## 6. axiosを使ってPOST通信

```components/ContactForm/index.jsx
// axios
import axios from 'axios'

// 先ほど作成したGoogleFormの情報
import { ContactGoogleForm } from '@/constants/ContactGoogleForm'

// ~~~~ 中略 ~~~~

const submit = (values) => {
  // ReactHookFormは、hundleSubmitに渡した関数に、
  // registerを利用して登録した各Inputの値をObjectとして渡されてくる。
  // values.nameやvalues.genderと呼び出せる。便利ですね！

  const GOOGLE_FORM_ACTION = ContactGoogleForm.action
  // CORS対策は必須
  const CORS_PROXY = 'https://cors-anywhere.herokuapp.com/'

  // PostのParm生成
  const submitParams = new FormData()
  submitParams.append(ContactGoogleForm.name, values.name)
  submitParams.append(ContactGoogleForm.gender, values.gender)
  submitParams.append(ContactGoogleForm.inquiry, values.inquiry)

  // 実行
  axios
    .post(CORS_PROXY + GOOGLE_FORM_ACTION, submitParams)
    .then(() => {
      window.location.href = '/thanks' // 成功時
    })
    .catch((error) => {
      console.log(error) // 失敗時
    })
}
```

## ちゃんと、GoogleFormに飛んでますね！
- 実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317515/c471a80b-9b8f-630c-e1e1-3abf25d553b9.png)

- 確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317515/8ee55a79-d085-ac10-c3fc-b58620f1a59c.png)


## （参考） Slack通知を実現

- [Slack通知](https://qiita.com/pchan52/items/574e930a3cc42cf7f8b9)

# 感想

これはこれで簡単に見た目作れるので、ミニマムでいいですよね。
Formとしての機能はGoogleFormで今回の用途としては必要十分でした。

# 参照
- [【Netlify】Forms機能を利用して問い合わせフォームを作成する](https://qiita.com/NaokiIshimura/items/bce2f0b865ec1bc16a53)
-  [Googleformからのslack通知設定方法
](https://qiita.com/pchan52/items/574e930a3cc42cf7f8b9)