0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.js+ヘッドレスCMSではじめたアプリのお問い合わせページをフォーム作成ツール formrun で作ってみた

Last updated at Posted at 2024-12-28

解決すべき問題

翔泳社刊 『Next.js+ヘッドレスCMSではじめる!かんたんモダンWebサイト制作入門』を読んだ。

L

第9章「お問い合わせページを作ってみよう」はReactとNext.jsで作ったアプリを CRMツール HubSpot のフォーム作成管理機能と連携させる方法を紹介している。しかし私はHubSpotが自分の手に余ると感じた。もっと軽い別のサービスを試したいと思った。ググったらmicroCMS社の松田承一さんの記事 『microCMSを使ったサイトでお問い合わせ機能を用意する方法』 を見つけたので読んだ。そこでひとつの候補として フォーム作成ツール formrun があげられていた。やってみよう。

第9章で作ったReactアプリのお問い合わせページにformrunで作成したwebフォームを埋め込みたいが、どうすればいいのか?

解決方法

formrun社による説明を読んだ。

formrunはひとつひとつのフォームに固有のURLを割り当てる。URLの形式はこうだ。

https://form.run/@XXXXXXX-XXXXXXX-XXXXXXXXXXXXXXXXXXXX

以下の説明において、XXXXXXXの部分はあなたのフォームに割り当てられた具体的な文字列に置き換えてください。

formrunの説明には、わたしのWebサイトページのHTMLの中に次のような断片を埋め込めばいい、と書いてあった。

<script src="https://sdk.form.run/js/v2/embed.js"></script>
<div
  class="formrun-embed"
  data-formrun-form="@XXXXXXX-XXXXXXX-XXXXXXXXXXXXXXXXXXXX"
  data-formrun-redirect="false">
</div>

このHTML断片が何を意図しているのか? <script src="https://sdk.form.run/js/v2/embed.js"> が実行されれば embed.js が動いて 直後の <div> 要素の中に <iframe> 要素を挿入するだろう。 その <iframe> はformrunが提供するwebフォームのURLを参照するので、結果的にwebページの中にwebフォームが埋め込まれて表示されるだろう。

はじめ、わたしはこの説明を素朴に受けとめた。ContactFormコンポーネントのTypeScriptの中に上記のHTML断片をJSX構文で記述した。しかしこのベタなやり方は通用しなかった。なぜか?

WebページのHTMLソースに書かれた <script> タグはReactによる制御の外側(step outside of React)にある。Reactで構築された「お問い合わせページ」がブラウザの上で表示されたとしても <script> は実行されない。<script> 要素のsrc属性が指すJavaScriptコードはダウンロードすらされない。これではダメだ。

では、どうすればいい?

お問い合わせ画面を実装するReactコンポーネントが描画されたタイミングでReactのフックを起動しよう。副作用フック useEffect 関数を使え。ブラウザ上でお問い合わせページのコンポーネントが開かれたタイミングを useEffect関数で捉えてカスタムfunctionを起動しよう。カスタムfunctionが DOM APIを使って <iframe> を動的に挿入すればいい。

説明

formrunでフォームを作れ

formrun にあなたのアカウントを作ろう。ひとつ、問い合わせフォームを作成しよう。formrunとは何か、どう操作するのか、といった説明はここではしない。彼らの説明を読んで従えばいい。サンプルのテンプレートを選んでボタンを数回クリックすればマジで数分でフォームを作ることができる。

ちなみにformrunはひとつひとつのフォームに固有のURLを割り当てる。形式はこんな感じ:

https://form.run/@XXXXXXX-XXXXXXX-XXXXXXXXXXXXXXXXXXXX

ここでXXXの部分はあなたのフォームに割り当てられた具体的な文字列に置き換えてください。

このURLのパス部分つまり https://form.run/ に続く @ を含む文字列を「問い合わせ」ページのHTMLの中に埋め込むことによって、あなたのサイトとformrunを連携させることができる。

環境変数を定義せよ

プロジェクトのディレクトリに(すなわち package.json ファイルの隣に) .env.local ファイルを作れ。 .env.local ファイルの中で環境変数 NEXT_PUBLIC_FORMRUN_FORM_URL_PATH を定義しよう。

NEXT_PUBLIC_FORMRUN_FORM_URL_PATH=@kazuXXXXXXXXX-XXXXXXXXXXXXXXXXXXX

この環境変数の値として formrunが生成したあなたのフォームのURLのパス文字列を設定します。

ひとつ注意点がある。この環境変数の名前を NEXT_PUBLIC_ で始まるものにしなければならない。サーバー上で定義された環境変数をブラウザ上で動くJavaScriptが参照できるようにするためだ。詳しくはNext.jsのドキュメントを参照のこと。

ContactFormコンポーネントを書き直す

『Next.js+ヘッドレスCMSではじめる!かんたんモダンWebサイト制作入門 』 の第9章に掲載されたContactFormコンポーネントを書き直した。

ContactFormコンポーネントが描画されたとき useEffect 関数を利用してHTMLのDOMを動的に書き換えて <iframe> を挿入するようにした。

"use client";

import styles from "./index.module.css";
import { useEffect } from 'react';

export default function ContactForm() {
  if (!process.env.NEXT_PUBLIC_FORMRUN_FORM_URL_PATH) {
    throw new Error("NEXT_PUBLIC_FORMRUN_FORM_URL_PATH is required");
  }
  useEffect(() => {
    console.log(`The ContactForm compnent was rendered`)
    /* generate the following stuff in the DOM
    <div id="embededForm">
      <script src="https://sdk.form.run/js/v2/embed.js" async></script>
      <div
        class="formrun-embed"
        data-formrun-form=`${NEXT_PUBLIC_FORMRUN_FORM_URL_PATH}`
        data-formrun-redirect="false">
      </div>
    </div>
    */
    const form = document.getElementById("embededForm");
    const containerDiv = form?.querySelector('div'); // child div element
    if (containerDiv === null) { // insert iframe only if it is not yet there
      const script = document.createElement("script");
      script.setAttribute("src", "https://sdk.form.run/js/v2/embed.js");
      script.async = true;
      form?.appendChild(script);

      const embed = document.createElement("div");
      embed.className = "formrun-embed";
      embed.setAttribute("data-formrun-form", `${process.env.NEXT_PUBLIC_FORMRUN_FORM_URL_PATH}`);
      embed.setAttribute("data-formrun-redirect", "false");
      form?.appendChild(embed);

      return () => {
        form?.removeChild(script);
      }
    }
  }, []);

  return (
    <>
      <div id="embededForm" className={styles.form}></div>
    </>
  );
}

このコードについて留意点を述べる。

  • このコードはサーバ上ではなくブラウザ上で実行されなければならない。だから冒頭に "use client" を書いている。

  • フォームのURLのPath部分を環境変数から読み込んでいる。<iframe src="…​"> が参照するURLを組み立てるために。

  • ReactがContactFormコンポーネントを1回だけcallするとは限らない。わたしの環境では常に2回callしている。どうして2回callするのか、理由をわたしは知らない。理由はともかく、2回目以降のcallで <iframe> を挿入するのを避けるように if 文で制御している。

ちなみに、本の第9章ではHubSpotを前提として問い合わせフォームを実装するために app/_actions/contact.ts などいくつかのファイルを追加している。formrunに合うようにそれら周辺のファイルも修正した。

サーバーを起動せよ

いつものように

$ cd プロジェクトのディレクトリ
$ npm run dev

とやろう。

ブラウザでサイトを見る

ブラウザで

を開け。すると下記のような画面が表示されるはず。

contact view

ここに表示されているフォームはformrunによって作成されたものだ。

F12キーでDeveloper Toolを開きDOMツリーを眺めてみよう。

contact DOM

確かに <iframe> 要素が挿入されていて、iframeのsrc属性がformrunによって公開されたURLを指していることを確認することができた。

結論

翔泳社刊 『Next.js+ヘッドレスCMSではじめる!かんたんモダンWebサイト制作入門』の第9章と同じようなお問い合わせフォームをフォーム作成ツール formrun で実装することを試みて成功した。Next.js+microCMS+formrunの組み合わせは素晴らしく楽チンだ。

参考

GitHubでプロジェクトを公開しました。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?