【React】inputを動的に増やせるform【React Hook Form】

React Hook Form を導入していない場合は、
ターミナル(コマンドプロンプト・PowerShell)にて
cd ディレクトリ名 を使って プロジェクトディレクトリ に移動し、

 npm i react-hook-form

または

 yarn add react-hook-form

プロジェクトに Reac Hook Form を導入しましょう。

目次

完成コード

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

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

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

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

  // submitボタンを押した時に行う処理
  const onSubmit = (data) => {
    const list = [];
    data.tasks.forEach((item, index) =>
      list.push(`\nタスク番号${index}:${item.taskValue}`)
    );
    // 送信後 input の入力欄を初期化
    reset();
  };

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

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

  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`)} />
          </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;

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

ライブラリからの呼び出し

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

React Hook Form を使うための基本設定

// React Hook Form を使うための基本設定
const { register, handleSubmit, reset, control } = useForm({
  // input の value の 初期値を設置
  defaultValues: {
    tasks: [{ taskValue: '' }],
  },
});
  • register, handleSubmit までは React Hook Form を使うために必須
  • reset は submit(送信)ボタンを押して送信後に input から入力欄を初期化して消すのによく使う
  • control は input を動的に増減する場合は必要
  • getValues は 後述するおまけ機能「input入力中にバックスペースで input を減らす」に使う(使わない場合は不要

defaultValues: {}内の tasks・taskValueは任意のキー名を指定できますが、以降のコードに出てくるtasks・taskValue の箇所をそれぞれ指定したキー名に置き換えてください

動的に増減する.・しない input ごちゃ混ぜの場合のサンプル 【ここをクリック・タップで表示】
// React Hook Form を使うための基本設定
const { register, handleSubmit, reset, control, getValues } = useForm({
  // input の value の 初期値を設置
  defaultValues: {
    title: '', 
    completed: false,
    tasks: [{ taskValue: '' }],
    categorys: [{ cat: '' }],
  },
});
  • input が動的に増減するキーは、defaultValues: {}内で キー名: [{ valueキー名: 初期値 }] の後にカンマ「,」を挿入
  • 増減しないキーは、キー名: 初期値 の後にカンマ「,」を挿入

input を動的に増減させるための設定

// input を動的に増減させるための設定  
const { fields, prepend, append, remove } = useFieldArray({
  control,
  name: 'tasks',
});
  • fields は動的に input を増減する根幹となる関数
  • prepend は input を前に順々に追加していく関数(あまり使わない)
  • append は input を後ろに順々に追加していく関数(こっちのほうがよく使う)
  • remove は input を減らす関数

使う関数は記述し、使わない関数は記述不要

useFieldArray({})内の control,必須
name: ‘キー名’, は先程指定した動的に input を増減させるキー名を記述

※input を増減させないキーは name: ‘キー名’ を記述しない

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

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

console.log(data);
const list = [];
data.tasks.forEach((item, index) => list.push(\nタスク番号${index}:${item.taskValue}));
の部分は仮置きした確認用です
submitボタンを押した際に行いたい任意の処理に置き換えてください

reset(); submitボタンを押して送信後 input の入力欄を初期化します
初期化しないと入力欄に入力した内容が残り、続けて入力する場合、手動で書き換えたり消す手間が発生します

減らすボタンを押した時に行う処理

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

// input を減らすボタンを押した時の処理
const reduce = () => {
  if (count > 0) {
    remove(count);
    setCount(count - 1);
  }
};
  • useState() を使い input をいくつ追加したカウントします(引数は0)
  • remove()メソッドは引数がないと動的に増減する input を全て消します
  • 先程宣言した count を引数に入れることで後ろから順々に減らすようにします
  • remove()メソッドはデフォルトでは最終的に初期設置されている input も消してしまうので、if (count > 0)で阻止し1つは input が残るようにします

return() 内部(コンポーネント出力本体)のコード解説

<form>

<form onSubmit={handleSubmit(onSubmit)}>
...
</form>

React Hook Form を使う上での定型文のようなものです
submit(送信)ボタンが押された時に行われる処理の関数を指定します

React Hook Form では <button type=submit onClick={onSubmit}> のように submitボタン の方に押した際の関数を指定しません

動的に増減する input

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

{fields.map()}内で key={field.id} の付いた html の タグで挟み込みます

React では thml のように <label for={...}> と記述できません
(for は他役割が予約せれているから)

React では htmlFor を使い、
<label htmlFor={`キー名.${index}.valueキー名`}> のように記述します

<input {…register(`キー名.${index}.valueキー名`)} /> で複製される input を指定します

※ 上記のhtmlFor で指定した `キー名.${index}.valueキー名`
…register() 内の`キー名.${index}.valueキー名` は同じものを指定してください

追加ボタン

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

<button>タグは type='buttton' に指定しないと form内では submitボタンとして扱われます
逆に submitボタンは type='submit' にします

押した際の関数指定は onClick={() => append({ valueキー名: 初期値 })} のようにします

prepend(前に追加)ボタンもほぼ同様です

最後まで読んでくださりありがとうございました。シェア頂けると嬉しいです!
  • URLをコピーしました!
  • URLをコピーしました!

ABOUT ME

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

コメント

コメントする

CAPTCHA

目次