LoginSignup
14
6

More than 5 years have passed since last update.

ReactでNetlifyのFormsを利用する方法

Last updated at Posted at 2018-08-06

Reactで作ったプロジェクトをNetlifyでホスティングしている時に、NetlifyのFormsを使おうと思ったら素直には行かなかったので。

「ここ」に書いてあることです。

通常NetlifyでFormsを利用する場合は、formnetlify属性を追加することでNetlifyがHTMLをパースする時にコレを読み取ってFormsが利用できるようになりますが、残念ながらReactのプロジェクトでは単純にJSXにnetlify属性を追加しただけではFormsを利用することはできません。

シンプルにフォームを作成する

1番簡単にReactでフォームを実装する方法は次のような形になります。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Contact</title>
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">

      ReactDOM.render(
        <form name="contact" method="post">
          <p>
            <label>Your Name: <input type="text" name="name"/></label>
          </p>
          <p>
            <label>Your Email: <input type="email" name="email"/></label>
          </p>
          <p>
            <label>Message: <textarea name="message"></textarea></label>
          </p>
          <p>
            <button type="submit">Send</button>
          </p>
        </form>,
        document.getElementById("root")
      );

    </script>
  </body>
</html>

コレを元に進めて行きます。

静的なHTMLのフォームをサイトに追加する

JSXに記述してもFormsを利用することはできないため、NetlifyにFormsの利用を知らせるために静的なHTMLのフォームをソースに追加します。(public/index.htmlなど)


<!-- A little help for the Netlify post-processing bots -->
<form name="contact" netlify netlify-honeypot="bot-field" hidden>
  <input type="text" name="name" />
  <input type="email" name="email" />
  <textarea name="message"></textarea>
</form>

ここで出て来たnetlify-honeypotは、ユーザーが利用する際にcaptchaを表示しないようにするオプションです。

JSXのformにhidden属性のform-nameフィールドを追加する

フォームの名前をNetlifyに知らせるためのhidden属性のinputを追加します。

次の例であれば、Netlifyのダッシュボードでは、contactという名前でフォームを確認することができます。

<input type="hidden" name="form-name" value="contact" />

最終的なコードは以下のようになります。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Contact</title>
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
  </head>
  <body>

    <!-- A little help for the Netlify bots if you're not using a SSG -->
    <form name="contact" netlify netlify-honeypot="bot-field" hidden>
      <input type="text" name="name" />
      <input type="email" name="email" />
      <textarea name="message"></textarea>
    </form>

    <div id="root"></div>
    <script type="text/babel">

      ReactDOM.render(
        <form name="contact" method="post">
          <input type="hidden" name="form-name" value="contact" />
          <p>
            <label>Your Name: <input type="text" name="name"/></label>
          </p>
          <p>
            <label>Your Email: <input type="email" name="email"/></label>
          </p>
          <p>
            <label>Message: <textarea name="message"></textarea></label>
          </p>
          <p>
            <button type="submit">Send</button>
          </p>
        </form>,
        document.getElementById("root")
      );

    </script>
  </body>
</html>

自前のサンクスページを実装する

NetlifyのFormsでお問い合わせを投げるとデフォルトのサンクスページが出て来ます。

コレを変えたかったのですが、公式のドキュメントを読むと、formactionでサンクスページを指定すればいいよ!みたいに書いていたんですが、ダメだったので違う方法で実装しました。

statefulにする

まず、上記のフォームをstatefulにすると以下のようになります。

<script type="text/babel">

  const encode = (data) => {
    return Object.keys(data)
        .map(key => encodeURIComponent(key) + "=" + encodeURIComponent(data[key]))
        .join("&");
  }

  class ContactForm extends React.Component {
    constructor(props) {
      super(props);
      this.state = { name: "", email: "", message: "" };
    }

    /* Here’s the juicy bit for posting the form submission */

    handleSubmit = e => {
      fetch("/", {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: encode({ "form-name": "contact", ...this.state })
      })
        .then(() => alert("Success!"))
        .catch(error => alert(error));

      e.preventDefault();
    };

    handleChange = e => this.setState({ [e.target.name]: e.target.value });

    render() {
      const { name, email, message } = this.state;
      return (
        <form onSubmit={this.handleSubmit}>
          <p>
            <label>
              Your Name: <input type="text" name="name" value={name} onChange={this.handleChange} />
            </label>
          </p>
          <p>
            <label>
              Your Email: <input type="email" name="email" value={email} onChange={this.handleChange} />
            </label>
          </p>
          <p>
            <label>
              Message: <textarea name="message" value={message} onChange={this.handleChange} />
            </label>
          </p>
          <p>
            <button type="submit">Send</button>
          </p>
        </form>
      );
    }
  }

  ReactDOM.render(<ContactForm />, document.getElementById("root"));

</script>

サンクスページへ遷移させる

react-routerを使いました。

適当にサンクスページを作って、パスを/thanksのようにします。

ここで、alert("Success!")の部分がsubmit成功時に呼ばれるところなんですが、ここで/thanksに飛ばしてあげます。

historyを使ってサンクスページに飛ばすようにしたところ、上手く動きました。
withRouterでラップするのも忘れないようにしてください。

import { withRouter } from 'react-router';
.
.
.

fetch("/", {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: encode({ "form-name": "contact", ...this.state })
    })
      .then(() => this.props.history.push('/thanks'))
      .catch(error => alert(error));

.
.
.

export default withRouter(Component);

以上になります、もっといい方法があるよ!という方いらっしゃったら是非コメント頂きたいです。

14
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
6