9
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

Organization

React hookで気持ちよく入力チェック〜エラー判定を行う

突然ですがこういうフォームっていいですよね!

  • 入力が終わると、エラーかどうかを判定してエラー文を表示してくれる
  • 正しい入力に戻ると、エラー文が消える

gifにするとこういう感じ!

comp.gif

シンプルですが、「どういう風に書けばこうなるか」は案外知らないと作れないと思います

今回はこういうフォームの作り方をさくっとまとめます

要点をまとめると

  • onChangeで、「入力値」をuseStateへ保存する
  • onBlurで、「入力値を判定したエラー文」をuseStateへ保存する

これがわかればできます!

実装

では書いていきます

まずHTMLですが、「ラベル(はなくてもいいけど)」「入力欄」「エラー文を出す場所」があればいいです!

<div>
  <label>unique name</label>
  <input
    type="text"
    name="name"
    placeholder="Enter your name"
  />
  <p>error</p>
</div>

次にここへuseStateのロジックを混ぜていきましょう!

const [name, setName] = useState('')
const [nameError, setNameError] = useState('')

return (
  <div>
    <label>unique name</label>
    <input
      type="text"
      name="name"
      placeholder="Enter your name"
      value={name}
      onChange={(e) => {
        setName(e.target.value)
      }}
    />
    {nameError && <p>{nameError}</p>}
  </div>
)

一気に増えましたが、大事なところだけ解説します!

まずuseStateで、必要なパラメーター「入力値」「入力値エラー」を作ります

const [name, setName] = useState('')
const [nameError, setNameError] = useState('')

inputタグのvalueとonChange属性にnameとsetNameを渡すことで、useStateの値と、入力フォームの中身を一致させることができます

<input
  type="text"
  name="name"
  placeholder="Enter your name"
  value={name}
  onChange={(e) => {
    setName(e.target.value)
  }}
/>

次にエラー文。ちょっと慣れない書き方かもしれませんが、こういう風に書くと「nameErrorがfalseじゃない時」つまり、エラー文が存在する時だけ、うしろのpタグの中身を出してくれます

jsxならではの書き方ですね

{nameError && <p>{nameError}</p>}

最後の仕上げです!

onBlur属性の関数を定義して、入力フォームから離れた時に、入力値を判定して、エラー文を表示できるようにします

const [name, setName] = useState('')
const [nameError, setNameError] = useState('')

const handleBlur = (e) => {
  const name = e.target.value
  if (!name) {
    setNameError('required')
  } else if (name.length < 5) {
    setNameError('should longer than 5')
  } else {
    setNameError()
  }
}

return (
  <div>
    <label>unique name</label>
    <input
      type="text"
      name="name"
      placeholder="Enter your name"
      value={name}
      onChange={(e) => {
        setName(e.target.value)
      }}
      onBlur={handleBlur}
    />
    {nameError && <p>{nameError}</p>}
  </div>
)

onBlurは他のところをクリックした時など、入力を中断した時だけ走ってくれるので、入力中には動作しません

また嬉しい点として、入力途中でボタンをクリックしても、ボタンのクリックイベントより先にonBlurが走ってくれるので、うっかり変なデータを送信することもありません!

main2.gif

ボタンも一緒に作る場合は、disabledを設定しておくと良いでしょう。(nameErrorが存在する時にdisabledがtrueになるようにする)

const [name, setName] = useState('')
const [nameError, setNameError] = useState('')

const handleBlur = (e) => {
  const name = e.target.value
  if (!name) {
    setNameError('required')
  } else if (name.length < 5) {
    setNameError('should longer than 5')
  } else {
    setNameError()
  }
}

return (
  <div>
    <label>unique name</label>
    <input
      type="text"
      name="name"
      placeholder="Enter your name"
      value={name}
      onChange={(e) => {
        setName(e.target.value)
      }}
      onBlur={handleBlur}
    />
    {nameError && <p>{nameError}</p>}
  </div>
  <div>
    <button disabled={nameError}>Save</button>
  </div>
)

おまけ:入力値が空の時のe.target.value

...へは「空文字」が渡ってきます。

というより基本的にはe.target.valueは、数字を書いたとしても、基本全て文字列で渡ってきます(e.target.valueAsNumberというのもありますが、それはまた別の話ということで...)

つまり「文字列型」なので、今回のようなnameと行った文字列の入力値なら良いのですが、数字を扱いたい場合は都合が悪いです

なので、そういう場合はonChangeで仲介してあげましょう!

入力値が数字の場合の「空」をどう表現するかは人によると思うのですが、私はundefinedを使っています!

// 年齢のフォーム

<input
  type="number"
  name="age"
  placeholder="Enter your age"
  value={age}
  onChange={(e) => {
    if (e.target.value === '') {
      setAge(undefined)
    } else {
      // 入力値を数値へ変換!
      setAge(Number(e.target.value))
    }
  }}
/>

終わりに

今回はuseStateとinputのイベントハンドラを使って、エラー文を綺麗に出すフォームを作ってみました!

CSSやアニメーションをもっと付ければ、より洗練された感じになるので、是非やってみてください!

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
9
Help us understand the problem. What are the problem?