LoginSignup
0

More than 5 years have passed since last update.

Reactのイベントまわりでハマったこと2点

Posted at

React.jsでイベントを扱っていたところ、引っかかったところが2箇所ほどありました。

非同期なsetStateとイベントオブジェクト

前のstatepropsを見て、その値をもとにsetStateをかけたい場合、setStateに関数を渡して、その中で新しいstateを作ることが推奨されています。ただし、このコールバックは非同期で実行されます。

失敗例
handleChange = (e) => {
  this.setState(prevState => {
    return /* e.target.valueも使って新たなstateを計算 */;
  });
}

このように、setStateの関数内でイベントオブジェクトを使ってしまうと、関数が実行されるタイミングではeはすでに無効となってしまっていますsetStateに入る前に、イベントオブジェクトから必要な値を確保しておきましょう。

対策した例
handleChange = (e) => {
  const {value} = e.target;
  this.setState(prevState => {
    return /* valueも使って新たなstateを計算 */;
  });
}

外側のクリックでドロップダウンを閉じる

例えばタイトルのような処理を組みたい場合に、Reactで管理しているわけではない外側にイベントを仕掛けざるを得ない場面もあります(componentWillUnmountできちんと消す必要があります)。そして、外側にセットしたイベントの側で、.containsを使ってReactコンポーネントの内側だったら無視…というように仕掛けたつもりだったのですが、「動的に削除したエレメントが内側だと認識されない」という、以前にRiotでハマったのと同様の問題を食らってしまいました。

display: noneも一案ではありますが、どうしようもない場合にはイベントを無効化したくなるかもしれません。ただ、そこも一筋縄では行きません。

Reactではイベントをシミュレーションして、すべてdocument直下に仕掛けているので、document.bodyなどに仕掛けたイベントは、Reactのイベントが動く頃にはすべて実行済みです。componentDidMountdocumentに仕掛ければ、Reactより後にセットできますが、イベントキャンセル時にはe.nativeEvent.stopImmediatePropagation()が必要となります(ネイティブ側でのキャンセルが必要なのと、Reactでは同じエレメントに複数イベントを仕掛けることがないので、ReactのイベントオブジェクトにはstopImmediatePropagationがないことに要注意です)。

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