Published on

最近のメモ(入力フォームとか)

Authors

転職してから約 3 ヶ月

せっかくイヤホンを買ったんですが、8 月からコロナのあおりやら何やらでリモート勤務となりました。
通勤しないことがこんなにも快適とは…

気軽にコミュニケーションとれるので気になったことはドンドン連絡して確認してます。
日は浅いけど、みんな良い人でとても働きやすい。
ポジションがディレクターというか PM というかなので、既存の案件は流れに乗るのが難しいけど、良い刺激をもらって働けています。

相変わらず個人でも案件をもらってて、先日はライブ配信の技術周り兼カメラ+スイッチャーなんかもやりました。
ありがたいことです!

それと今はコーポレイトサイトのコーディングを空き時間にやっています。

このブログも Gatsby で作ったし、React 公式が言うように

Gatsby は React で静的なウェブサイトを作成するのに最も良い方法です。 React コンポーネントを使用しながらも、事前レンダーされた HTML と CSS を出力することで最速のロード時間を保証します。

ということで Gatsby を使って作っています。
普通の FTP サーバーなので、パフォーマンスどうかなぁと思ってたけど、なかなか良い感じです。

そのサイトで入力フォームを作ったのですが、備忘録として。
コンポーネント細かく分けたほうがいいかなとか、もっと綺麗に書けそうと思うのですが…
アドバイスありましたら教えてください〜。

入力フォームのメモ

フォームとしては、お問い合わせの機能となります。
まだ送信方法が確定していないので、Gatsby で実装しやすい Getform を使いました。

Getform のセッティング

まず公式サイトでアカウントを作成します。
自分のダッシュボードに入り、Createをクリックしてエンドポイントを作成します。
名前は分かりやすいものをつけて、Timezone は Tokyo としました。
getform create endpoint

そうしてできたエンドポイントを

title=contact.js_getformサーバーと通信
const [serverState, setServerState] = useState({
      submitting: false,
      status: null
    });
const handleServerResponse = (ok, msg, form) => {
  setServerState({
    submitting: false,
    status: { ok, msg }
  });
  if (ok) {
    form.reset();
  }
};
const handleOnSubmit = e => {
      e.preventDefault();
      const form = e.target;
      setServerState({ submitting: true });
      axios({
        method: "post",
        url: "https://getform.io/f/{ここにエンドポイントを入れてね}",
        data: new FormData(form)
      })
    };

こんな感じにフォームのコンポーネントで設定します。
エンドポイントに form の post メソッドで入力内容を飛ばします。
このあとに.then や.catch でサーバーのレスポンスに応じた挙動を設定できます。
詳しくは公式サイトに書いてあります。
色んな環境での使い方が載っているので便利です!

バリデーションチェック

ここは色んなサイトを参考に作ったので、ベストプラクティスではないかと思います。
何か改善箇所があれば教えて下さい。

項目としては、名前、フリガナ、電話番号、メールアドレス、メッセージと標準的なものです。
contact form image

ここで扱うデータは、
・入力された情報
・エラーの表示
です。 各項目毎に useState で設定してあげます。

title=contact.js_フォームの数だけ入力値とエラー表示を作る
//名前の項目であればこんな感じ
//名前のinputタグに入力されるもの
const [name, setName] = useState('')
//名前に入力されたものを判定して、エラー表示するもの
const [nameError, setNameError] = useState('')

そしたら return の中に jsx で要素を書いてあげます。

title=contact.js_returnの中
<form onSubmit={handleOnSubmit}>
                    <label for="name">
                    <span>お名前</span>
                    <input type="text" name="name" placeholder="お名前" value={name}
                        onChange={(e) => {
                            setName(e.target.value)
                        }}
                        onBlur={nameBlur}
                    />
                    </label>
                    {nameError && <p>{nameError}</p>}

            <!-- 他の項目も同じように書いてあげる -->
</form>

これで入力された項目とエラー表示を扱うことができるようになりました。
自分は全ての項目で不備が無いことを確認できたら「送信」ボタンが押せるようにしました。

title=contact.js_入力内容のチェック
const [submitClick, setSubmitClick] = useState(true)
//無限レンダリング防止のuseEffect
useEffect(() => {

    //名前のチェック
    if (name && name.length < 4){
        setNameError('名前が短すぎます')
    } else if (name) {
        setNameError()
    }

    //カタカナのチェック
    const furiganaExp = /^([--\u3000]*)$/;
    if (furigana && furigana.length < 4){
        setFuriganaError('名前が短すぎます')
    } else if(furigana && !furiganaExp.test(furigana)){
        setFuriganaError('カタカナで入力してください')
    } else if (furigana) {
        setFuriganaError()
    }

    //番号のチェック
    const numExp = /^\d*$/;
    if (!numExp.test(telephone)){
        setTelephoneError('半角数字(ハイフンなし)で入力してください')
    } else if(telephone && telephone.length < 10){
        setTelephoneError('番号が短すぎます')
    } else if (telephone) {
        setTelephoneError()
    }

    //mailのチェック
    const emailExp = /^[A-Za-z0-9]{1}[A-Za-z0-9_.-]*@{1}[A-Za-z0-9_.-]{1,}.[A-Za-z0-9]{1,}$/;
    if (email && !emailExp.test(email)){
        setEmailError('メールアドレスを入力してください')
    } else if(email){
        setEmailError()
    }

    //メッセージのチェック
    if(message){
        setMessageError()
    }

    //全ての項目が入力されているか、エラーはないかチェックしてSendボタンのdisabledを設定
    if(name.length && telephone.length && email.length && message.length && furigana.length && nameError === undefined && furiganaError === undefined && telephoneError === undefined && emailError === undefined && messageError === undefined){
        setSubmitClick(false)
    }else{
        setSubmitClick(true)
    }
},[name, furigana, telephone, email, message, nameError, furiganaError, telephoneError, emailError, messageError]);

空欄かどうかは、useState の直下に書いて onBlur={nameBlur}で判定しています。

title=contact.js
const nameBlur = (e) => {
        const name = e.target.value
        if(!name){
            setNameError('お名前を入力してください')
        }
    }

一つのコンポーネントにこれらをつらつら書いたので、可読性が低いかなと思います。
そして、こうやってロジックの流れを改めて書くと、実際のコードが前後してしまうので難しいですね…
でもこれで入力が無い場合や内容が求めているのと異なる場合に、エラーを表示させることができました。
error image

「&&」でつなぎまくっている所は何か良い方法はないかなぁ。
配列に入れて、in で中身の判定もいいかなぁと思ったんですが、error のステイト値を配列に入れる記述が長くなるなぁと。

まだまだ勉強しなきゃ!

それではまた〜