YouTubeの「プログラミングチュートリアル」チャンネルの動画を参考に、Reactでログインフォームを作ってみました。今回はフロント部分のみで、バックエンドとのAPI連携はしていません。
ゴールとしては、「ユーザー名」「メールアドレス」「パスワード」を入力し、ログインできるようにします。その際にバリデーションチェックを行い、入力誤りがあればエラーを表示させます。
使用技術
React - 18.2.0
HTML
CSS
ファイル構成
- node_modules
- public
- src 
  -- App.css
  -- App.js
  -- index.css
  -- index.js
- packge.json
- gitinore
- yarn.look全体のコード(App.js)
// App.js
import { useState } from "react";
import "./App.css";
function App() {
  const initialValues = { username: "", mailAddress: "", password: "" };
  const [formValues, setFormValues] = useState(initialValues);
  //配列だと値しか入っていかない。objectならキーと値を入れることができる
  const [formErrors, setFormErrors] = useState({});
  // ログインボタンをクリックしたかどうか
  const [isSubmit, setIsSubmit] = useState(false);
  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormValues({ ...formValues, [name]: value });
    setIsSubmit(true);
  };
  const handleSubmit = (e) => {
    e.preventDefault();
    //ログイン情報を送信する
    //バリデーションチェックをする
    setFormErrors(validate(formValues));
  };
  //どの値をバリデーションチェックするのか→引数が必要
  const validate = (values) => {
    const errors = {};
    const regex =
      /^[a-zA-Z0-9_.+-]+@([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.)+[a-zA-Z]{2,}$/;
    if (!values.username) {
      errors.username = "ユーザー名を入力してください";
    }
    if (!values.mailAddress) {
      errors.mailAddress = "メールアドレスを入力してください";
    } else if (!regex.test(values.mailAddress)) {
      errors.mailAddress = "正しいメールアドレスを入力してください";
    }
    if (!values.password) {
      errors.password = "パスワードを入力してください";
    } else if (values.password.length < 4) {
      errors.password = "4文字以上15文字以下のパスワードを設定してください";
    } else if (values.password.length > 15) {
      errors.password = "4文字以上15文字以下のパスワードを設定してください";
    }
    return errors;
  };
  return (
    <div className="App">
      <form onSubmit={(e) => handleSubmit(e)}>
        <h1>ログインフォーム</h1>
        <hr />
        <div className="uiForm">
          <div className="formField">
            <label>ユーザー名</label>
            <input
              type="text"
              placeholder="ユーザー名"
              name="username"
              onChange={(e) => handleChange(e)}
            />
          </div>
          <p className="errorMsg">{formErrors.username}</p>
          <div className="formField">
            <label>メールアドレス</label>
            <input
              type="text"
              placeholder="メールアドレス"
              name="mailAddress"
              onChange={(e) => handleChange(e)}
            />
          </div>
          <p className="errorMsg">{formErrors.mailAddress}</p>
          <div className="formField">
            <label>パスワード</label>
            <input
              type="text"
              placeholder="パスワード"
              name="password"
              onChange={(e) => handleChange(e)}
            />
          </div>
          <p className="errorMsg">{formErrors.password}</p>
          <button className="submitButton">ログイン</button>
          {/* エラー文の数が0個なら */}
          {Object.keys(formErrors).length === 0 && isSubmit && (
            <div className="msgOk">ログインに成功しました</div>
          )}
        </div>
      </form>
    </div>
  );
}
export default App;コード解説
onChangeで入力情報を取得する
// App.js 
<div className="formField">
       <label>ユーザー名</label>
            <input
              type="text"
              placeholder="ユーザー名"
              name="username"
              onChange={(e) => handleChange(e)}
            />
</div>input への入力があった場合、onChange={(e) => handleChange(e)} で入力情報を取得する。
  const initialValues = { username: "", mailAddress: "", password: "" };
  const [formValues, setFormValues] = useState(initialValues);ReactHooksのuseState を 使用して、inputへ入力された文字列を格納する状態変数を設定する。useStateの初期値は、initialValues のオブジェクトを設定する。
formValues の文字列をinputへ入力されたタイミングで、username へ格納していく必要がある。なので、inputタグにonChange={(e) => handleChange(e)}を設定する。
// handleChange関数  
const handleChange = (e) => {
    const { name, value } = e.target;
    setFormValues({ ...formValues, [name]: value });
    setIsSubmit(true);
  };inputタグへ入力があるたびに、handleChange 関数が発火して、useState の formValue へ文字列が格納される。
usename ・ mailAddress ・ password を見分ける必要があるため、分割代入を使用し、const {name, value} = e.target でnameとvalueを取得する。
その後、スプレッド構文を使用して、formValues へ name と value を格納し、 useState の setFormValues へセットする。
ログインボタンをクリックしたら、ログイン情報を送信する
// App.js
<form onSubmit={(e) => handleSubmit(e)}>form タグへ onSubmit を設定し、ログインボタンがクリックされる度に、handleSubmit が発火される。
// App.js  
 //配列だと値しか入っていかない。objectならキーと値を入れることができる
 const [formErrors, setFormErrors] = useState({});
const handleSubmit = (e) => {
    e.preventDefault();
    //ログイン情報を送信する
    //バリデーションチェックをする
    setFormErrors(validate(formValues));
  };e.preventDefault() でクリック時の更新をなくす。
バリデーションチェックするために、空の配列 [formErrors, setFormErrors] を準備して、その中にエラーを格納していく。
オブジェクトにすることで、値だけでなく、キーと値を格納することができる。
setFormErrors で validate 関数を呼び出す。
// App.js  
//どの値をバリデーションチェックするのか→引数が必要
  const validate = (values) => {
    const errors = {};
    const regex =
      /^[a-zA-Z0-9_.+-]+@([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.)+[a-zA-Z]{2,}$/;
    if (!values.username) {
      errors.username = "ユーザー名を入力してください";
    }
    if (!values.mailAddress) {
      errors.mailAddress = "メールアドレスを入力してください";
    } else if (!regex.test(values.mailAddress)) {
      errors.mailAddress = "正しいメールアドレスを入力してください";
    }
    if (!values.password) {
      errors.password = "パスワードを入力してください";
    } else if (values.password.length < 4) {
      errors.password = "4文字以上15文字以下のパスワードを設定してください";
    } else if (values.password.length > 15) {
      errors.password = "4文字以上15文字以下のパスワードを設定してください";
    }
    return errors;
  };複数のパターンを const errors = {} でオブジェクトに格納することで、汎用性が上がる。
(!value.username) ユーザー名に入力がなかった場合。(!value.mailAddress) メールアドレスに入力がなかった場合、また、regex へメールアドレスの正規表現を格納し、正しい表記で入力されなかった場合もエラーを表示させる。
パスワードは、入力がなかった場合と4文字以下の時、15文字以上の時にエラーを表示させる。
ログインに成功したかどうか
//App.js
 // ログインボタンをクリックしたかどうか
 const [isSubmit, setIsSubmit] = useState(false);
 {/* エラー文の数が0個なら */}
 {Object.keys(formErrors).length === 0 && isSubmit && (
      <div className="msgOk">ログインに成功しました</div>
  )}ログインが成功する条件としては、エラーが0個 かつ ログインボタンをクリックしたか をクリアした時に成功となる。
エラーの keys の数を数えて0個ならOK(エラー文の数)。isSubmit でログインボタンをクリックしたかをチェックするが、初期値は false を設定し、handleSubmit が実行されたときに、true になる。
最後に
今回はログインフォームのフロント部分のみを学習の一環として制作をしました。今後は、バックエンドのAPIと連携させていく方法も学んでいきたいと思います。