【React】OnchangeとOnsubmitの違い

# はじめに
Reactのイベントハンドラである`Onchange`と`Onsubmit`について、いまいち違いが分からないまま使っていたところ、イベント登録処理が上手く動かなくなりました。
コードの修正を通じて、両者の違いについて少し解像度が高まったので、まとめておきます。
# 問題
**OnSubmit実行時にSelectBox上で選択した値が正確に登録できない**、という事象が発生しました。
より詳しく説明すると「登録処理自体は成功しているのに、**どのアイコンを選択しても毎回初期値が登録されてしまう**」といった状況です。

例）　`value="sad"` のアイコンを選択しても　`value="happy"` で登録されている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3675500/aa27383c-4171-4dac-fd90-4701b691b537.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3675500/fc2a8b1d-8502-8ec6-5017-0e0ee8bd92e5.png)

OnSubmitのみ設定されたコード

```tsx:page.tsx
//登録処理
  function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    const value = selectedValue.value;
    console.log(value);
    if (value) {
      const selectedOption = options.find((option) => option.value === value);
      if (selectedOption) {
        setSelectedValue(selectedOption);
      }
      //Supabaseに登録
      addMotivation(value);
    }
    setShowModal(false);
    console.log(selectedValue);
  }

//～アイコン選択＆登録部分～
　　　　　　　　　　　　　{/* アイコン選択部分 */}
                        <div className="mt-2">
                          <SelectBox
                            options={options}
                            selectedValue={selectedValue}
                          />
                        </div>
                        {/* 登録ボタンを押下するとonSubmitで値が登録される*/}
                        <form action="submit" onSubmit={handleSubmit}>
 
                          <div className="mt-5 sm:mt-6 sm:grid sm:grid-flow-row-dense sm:grid-cols-2 sm:gap-3">
                            <button
                              type="submit"
                              className="inline-flex w-full justify-center rounded-md bg-green-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600 sm:col-start-2 disabled:opacity-25"
                              disabled={selectedValue.value === ""}
                            >
                              登録
                            </button>
                            <button
                              type="button"
                              className="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:col-start-1 sm:mt-0"
                              onClick={handleCloseModal}
                            >
```
# 解決方法
**原因は、アイコン選択時の値（今回の場合はvalue）が`onSubmit`実行時に即座に反映されておらず、初期値である`value="happy"`が毎回最終的に登録されてしまっていました。**

Q.じゃあフォーム上の値が変更されたときに即座にステートに反映させるためにはどうするの？
**A.ここで`OnChange`を使います！**

***
まずReactでは、フォームの入力値を controlled component で管理する際、stateにフォームの現在の値を保持します。**このとき、`onChange`イベントを使って値が変わった瞬間に state を更新する必要**があります。

**`onSubmit` はフォーム全体が送信されたときに呼ばれるので、ユーザーがフォーム内のフィールドを編集した時点では実行されません。そのため、リアルタイムに入力内容を反映するには、各入力要素に `onChange` を設定しておく必要があります。**
`onSubmit` はフォーム送信時にすべての入力内容を処理する関数であり、フィールドの変化そのものをキャッチしていないからです。

**今回、選択した値をリアルタイムで取得するためには、`onChange`を使って選択された値を state にセットする必要があった**ということですね！

ということで既存の上記のコードに下記の処理を追加しました。
```tsx:page.tsx
//OnChange発火時
function handleSelectChange(value: OptionType | null) {
    if (value) {
      setSelectedValue(value);
    }
    console.log(value);
  }
  
//～アイコン選択＆登録部分～
　　　　　　　　　　　　　{/* アイコン選択部分にOnChange追加 */}
                        <div className="mt-2">
                          <SelectBox
                            options={options}
                            selectedValue={selectedValue}
                            onChange={handleSelectChange}
                          />
                        </div>
  ```
# まとめ
**・onSubmit
最終的なフォーム送信時に呼ばれるだけであり、リアルタイムの入力状態の更新には関与しない。**

**・onChange
フォームフィールドの値が変更された際にその変更を即座に state に反映させる。**

# 参考

https://qiita.com/omo_taku/items/e610d8d1de0df3dc291d