Reactで作ったプロジェクトをNetlifyでホスティングしている時に、NetlifyのFormsを使おうと思ったら素直には行かなかったので。
「ここ」に書いてあることです。
通常NetlifyでFormsを利用する場合は、form
にnetlify
属性を追加することで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でお問い合わせを投げるとデフォルトのサンクスページが出て来ます。
コレを変えたかったのですが、公式のドキュメントを読むと、form
のaction
でサンクスページを指定すればいいよ!みたいに書いていたんですが、ダメだったので違う方法で実装しました。
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);
以上になります、もっといい方法があるよ!という方いらっしゃったら是非コメント頂きたいです。