Reactでリストなどを実装する際などに、クリックされた要素に応じて処理を変えたいなどのケースに遭遇します。
以下の例においてhandleClickにおいて、クリックされた要素に関数情報が欲しい、といった状況です。
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にアロー関数を渡すという実装方法があります。
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を使って引数を増やすという手段もあります。
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要素から値を取得するという手段もあります。
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を使って任意の要素の値を取得することも可能です。
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
という差異がありました。
パフォーマンスの面におけるコールバック渡しとの優劣は現状つけられていませんが、比較的腑に落ちやすい実装方法に感じました。
まとめ
具体的なベストな手法を確定できていませんが、同様の課題に取り組んでいる方の参考に少しでもなれば幸いです。
閲覧ありがとうございました。