0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ドロップダウンメニューを実装してeventオブジェクトに非同期でアクセスする際にエラーが出た。

Posted at

今回、Reactでドロップダウンメニューを実装していて、詰まってしまった部分になります。

何が起こったか

824086e9e727e490924dcec88ceb2d42.gif

上記のように、ドロップダウンメニューを作成して、テストするか!というときにエラーが起きました。

1回目は選択できるのですが、2回目の選択でエラーになってしまう・・・。

書いたコード

今回、以下のような形で実装していました。


//ドロップダウンメニューの選択値によって値を変化させるためにuseStateを使う
//今回はドロップダウンメニューが複数あり、一つのuseState内でおさめたかったのでこんな感じで書いた
  const [selects, setSelects] = useState({
    name_id: 0,
    key_id: 0,
  })

//ドロップダウンメニュークリック時のイベントオプションを定義
  const handleDropdownChange = (event: any) => {
    const name = event.target.name
    setSelects(() => {
      return { ...selects, [name]: event.target.value }
    })
  }

//今回は配列からドロップダウンメニューを作成したかったので以下のように書く
//key_idも同じ用に書いてるので今回は省略
  List = names.map((a, index) => (
    <option value={`${a.name_id}`} key={index}>
      {a.name_id}
    </option>
  ))

//表示したい部分で下記のようにして表示
  <select name="name_id" onChange={handleDropdownChange}>
    {List}
  </select>

解決策

公式に書いてました。

参照できない理由

The SyntheticEvent is pooled. This means that the SyntheticEvent object will be reused and all properties will be nullified after the event callback has been invoked. This is for performance reasons. As such, you cannot access the event in an asynchronous way.

つまり、パフォーマンスの向上のために一度読み込まれたイベントオブジェクトは再利用されて、すべてのプロパティがnull化されてしまうので、非同期的にイベントにアクセスすることはできないということですね。

私が上記で一回目は問題なくドロップダウンメニューで選択できていたのは、イベントコールバックが一回目の呼び出しだったからで、二回目以降は最初に呼び出されたイベントオブジェクトが再利用されてしまうので、そのときに違う値が選択されているとエラーが発生する(=非同期的にアクセスできない)という理由だったみたいです。

というわけで解決策。解決策も公式に書いてました。

Note:
If you want to access the event properties in an asynchronous way, you should call event.persist() on the event, which will remove the synthetic event from the pool and allow references to the event to be retained by user code.

つまり、非同期でアクセスさせるためにはevent.persist()を使ってくれということです。

解決

//ドロップダウンメニュークリック時のイベントオプションを定義
  const handleDropdownChange = (event: any) => {
    event.persist(); //これを追加
    const name = event.target.name
    setSelects(() => {
      return { ...selects, [name]: event.target.value }
    })
  }

上記で解決!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?