LoginSignup
50
32

More than 3 years have passed since last update.

【React/TypeScript】onClickなどのイベント処理で要素ごとに引数を渡したい場合

Posted at

Reactでリストなどを実装する際などに、クリックされた要素に応じて処理を変えたいなどのケースに遭遇します。
以下の例においてhandleClickにおいて、クリックされた要素に関数情報が欲しい、といった状況です。

App.tsx
const App: React.FC = () => {
  const handleOnClick = () => {
    // クリックされた要素に応じた処理を行う。
  };
  return (
    <div className="App">
      <ul>
        {["dog", "cat", "rabbit"].map(v => (
          <li onClick={handleOnClick} key={v}>
            {v}
          </li>
        ))}
      </ul>
    </div>
  );
};

以下の記事において、イベント処理に引数を渡す際、主に3つのアプローチが取れるということがまとめられています。投稿者の方に感謝申し上げます。

今回はこちらの記事を参考に、要素ごとに異なる引数を渡したいというケースに絞り、自分が調べた内容を追加しつつ、React/TypeScriptで実装するサンプルを載せていきます。

検証環境のバージョン
"react": "^16.9.0",
"typescript": "3.5.3"

コールバックにアロー関数を渡す

もっともポピュラーな解決策として、onClickにアロー関数を渡すという実装方法があります。

App.tsx
const App: React.FC = () => {
  const handleOnClick = (v: string) => {
    console.log(v);
  };
  return (
    <div className="App">
      <ul>
        {["dog", "cat", "rabbit"].map(v => (
          <li onClick={() => handleOnClick(v)} key={v}>
            {v}
          </li>
        ))}
      </ul>
    </div>
  );
};

直感的かつ実装が用意なので、もっとも見かけることの多い実装方法でした。
ただ公式のイベント処理に関するドキュメントでも語られていますが、レンダリングのたびに関数が生成されることから、パフォーマンスを気にするような状況においては注意が必要となりそうです。

bindを使う

TypeScriptを使わない場合であれば、以下のようにbindを使って引数を増やすという手段もあります。

App.jsx
const App = () => {
  const handleOnClick = (v, e) => {
    console.log(v);
  };
  return (
    <div className="App">
      <ul>
        {["dog", "cat", "rabbit"].map(v => (
          <li onClick={handleOnClick.bind(this, v)} key={v}>
            {v}
          </li>
        ))}
      </ul>
    </div>
  );
};

ただ自分ではTypeScriptのレールに乗りつつ、適切な実装方法を見つけることができませんでした。
TypeScriptでbindを使うこと自体が個人的には怖いので、bindを使う方法については採用しない方針としました。

HTMLElementの属性から値を取得する

イベントを受け取った側で、イベント内のHTML要素から値を取得するという手段もあります。

App.tsx
const App: React.FC = () => {
  const handleOnClick = (e: React.MouseEvent<HTMLElement>) => {
    console.log(e.currentTarget.dataset.item);
  };
  return (
    <div className="App">
      <ul>
        {["dog", "cat", "rabbit"].map(v => (
          <li onClick={handleOnClick} key={v} data-item={v}>
            {v}
          </li>
        ))}
      </ul>
    </div>
  );
};

datasetだけではなく、getAttributeを使って任意の要素の値を取得することも可能です。

App.tsx
const App: React.FC = () => {
  const handleOnClick = (e: React.MouseEvent<HTMLElement>) => {
    console.log(e.currentTarget.getAttribute("data-item"));
  };
  return (
    <div className="App">
      <ul>
        {["dog", "cat", "rabbit"].map(v => (
          <li onClick={handleOnClick} key={v} data-item={v}>
            {v}
          </li>
        ))}
      </ul>
    </div>
  );
};

datasetを使った場合は戻り値がstring | undefined
getAttributeを使った場合は戻り値がstring | null

という差異がありました。
パフォーマンスの面におけるコールバック渡しとの優劣は現状つけられていませんが、比較的腑に落ちやすい実装方法に感じました。

まとめ

具体的なベストな手法を確定できていませんが、同様の課題に取り組んでいる方の参考に少しでもなれば幸いです。
閲覧ありがとうございました。

50
32
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
50
32