【React】input を入力中にキーボード操作で増減させる【React Hook Form】

目次

前提

↓前回の記事 に機能追加します
追加・減らすボタンを押した時以外に input入力中にエンター・空欄時にバックスペースで input を増減できるようにします

特定のキー入力で関数を作動

const onKeydown = (key) => {
  switch (key) {
    case 'Enter':
      // ここにエンターを押した時の処理を記述
      break;
    case 'Backspace':
      // ここにバックスペースを押した時の処理を記述
      break;
    default:
      break;
  }
};


<input onKeyDown={(e) => onKeydown(e.key)} />

上記でinput入力中にエンターキーなど特定のキーを押した際に関数を作動せることができます
しかし、このままでは漢字・予測変換選択中の確定させるためのエンターにも反応して意図しないタイミングで関数が作動します

return()まで(変数・関数宣言)コード

useForm から getValuesメソッドを追加

// React Hook Form を使うための基本設定
const { register, handleSubmit, reset, control, getValues } = useForm({

const {...} = useForm() の const の後の {} の中に getValues を追加します
input入力中にバックスペースを押した際の判定に使います

漢字変換・予測変換選択中か否かの判定

// 漢字変換・予測変換(サジェスト)選択中か否かの判定
const [composing, setComposition] = useState(false);
const startComposition = () => setComposition(true);
const endComposition = () => setComposition(false);

そこで上記で変換中か否かの判定を行い、変換を確定させるエンターに反応しないように振り分けます

キーボード操作時の関数

// input入力時にキーボード操作でinput欄を増減
const onKeydown = (e, key, index) => {
  const value = getValues(`tasks.${index}.taskValue`);
  switch (key) {
    // 変換中でない時に エンター で input を増やす
    case 'Enter':
      e.preventDefault();
      if (composing) break;
      append({ taskValue: '' });
      break;
    // input が空欄時に バックスペース で input を減らす
    case 'Backspace':
      if (index === 0) break;
        if (value === "") remove(count);
        setCount(count - 1);
      break;
    default:
      break;
  }
};

input入力中にエンターを押した際の処理

  • input入力中にエンターを押すとデフォルトでは submit(送信)になるのでe.preventDefault(); で阻止
  • if (composing) break;変換中なら、そのまま何も処理を行わない
  • その後のappend({ valueキー名: 初期値 });break;変換中でないなら、append()メソッドで input を後ろに追加

input入力中にバックスペースを押した際の処理

  • getValues()メソッドで input の value(入力内容)を取得(引数は キー名.${index}.valueキー名).
  • if (index === 0) break;で input を減らしすぎないように1つは残るようにする
  • if (value === "") remove(count);value が空欄の時だけ remove()メソッドで input を減らす

return() 内部での <input> のコード解説

<input
  {...register(`tasks.${index}.taskValue`)}
  onCompositionStart={startComposition}
  onCompositionEnd={endComposition}
  onKeyDown={(e) => onKeydown(e, e.key, index)}
/>
  • onCompositionStart={関数名}で変換”開始“時に作動する関数を指定
    • 今回は state の composing を true にし、変換中”である“と判定に切り替え
  • onCompositionEnd={関数名}で変換”終了“時に作動する関数を指定
    • 今回は state の composing を false にし、変換中”でない“と判定に切り替え
  • onKeyDown={(e) => onKeydown(e, e.key, index)}の引数を(e, e.key, index)にします

完成コード

サンプルはこちら CodeSandbox(外部サイト)

import { useState } from "react";
import { useForm, useFieldArray } from "react-hook-form";

function Form() {
  // React Hook Form を使うための基本設定
  const { register, handleSubmit, reset, control, getValues } = useForm({
    // input の value の 初期値を設置
    defaultValues: {
      tasks: [{ taskValue: "" }]
    }
  });

  // input を動的に増減させるための設定
  const { fields, prepend, append, remove } = useFieldArray({
    control,
    name: "tasks"
  });

  // submitボタンを押した時に行う処理

  const onSubmit = (data) => {
    console.log(data);
    const list = [];
    data.tasks.forEach((item, index) =>
      list.push(`\nタスク番号${index}:${item.taskValue}`)
    );
    // 送信後 input の入力欄を初期化
    alert(list);
    reset();
  };

  // input をいくつ追加したカウント
  const [count, setCount] = useState(0);
  const countUp = () => setCount(count + 1);

  // input を減らすボタンを押した時の処理
  const reduce = () => {
    if (count > 0) {
      remove(count);
      setCount(count - 1);
    }
  };

  // 漢字変換・予測変換(サジェスト)選択中か否かの判定
  const [composing, setComposition] = useState(false);
  const startComposition = () => setComposition(true);
  const endComposition = () => setComposition(false);

  const onKeydown = (e, key, index) => {
    const value = getValues(`tasks.${index}.taskValue`);
    switch (key) {
      // 変換中でない時に エンター で input を増やす
      case "Enter":
        e.preventDefault();
        if (composing) break;
        append({ taskValue: "" });
        break;
      // input が空欄時に バックスペース で input を減らす
      case "Backspace":
        if (index === 0) break;
        if (value === "") remove(count);
        setCount(count - 1);
        break;
      default:
        break;
    }
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <button
        type="button"
        onClick={() => [prepend({ taskValue: "" }), countUp()]}
      >
        前に追加
      </button>

      {fields.map((field, index) => (
        <div key={field.id}>
          <label htmlFor={`tasks.${index}.taskValue`}>
            タスク番号{index}:
            <input
              {...register(`tasks.${index}.taskValue`)}
              onCompositionStart={startComposition}
              onCompositionEnd={endComposition}
              onKeyDown={(e) => onKeydown(e, e.key, index)}
            />
          </label>
        </div>
      ))}

      <button
        type="button"
        onClick={() => [append({ taskValue: "" }), countUp()]}
      >
        後ろに追加
      </button>
      <br />

      <button type="button" onClick={reduce}>
        減らす
      </button>
      <br />

      <button type="submit">送信</button>
    </form>
  );
}
export default Form;
最後まで読んでくださりありがとうございました。シェア頂けると嬉しいです!
  • URLをコピーしました!
  • URLをコピーしました!

ABOUT ME

WEB制作者
スキル:HTML・Sass(FLOCSS)・JavaScript・jQuery・WordPress

コメント

コメントする

CAPTCHA

目次