はじめに
ReactとTypeScriptで学習記録アプリを作成しています。
追加機能として、表示している一覧から特定の行を削除するボタンを追加したところ、エラーが表示されたので解決方法をまとめます。
原因のコード
Button
タグのonClick
プロパティでエラーが発生しました。
ブラウザ側では、onClickDelete
関数のalert
関数が削除ボタンを押下しなくても実行される状態になり、無限ループに陥りました。
export const App = () => {
// 削除
const onClickDelete = async (id: string) => {
alert("削除を実行")
await DeleteRecord(id);
// 削除後のレコードを取得
const updateAllRecord = await GetAllRecords();
setRecords(updateAllRecord);
};
// 画面描画
return (
<Provider>
{records.map((record) => (
<Table.Row key={record.id}>
<Table.Cell>{record.learn_title}</Table.Cell>
<Table.Cell textAlign="center">
<Button onClick={onClickDelete(record.id)}>削除</Button>
</Table.Cell>
</Table.Row>
))}
</Provider>
)
};
解決方法
対応としては、onClick
にアロー関数を渡すことでエラーと無限ループが解消され、任意のレコードが削除されました。
// 一部省略
{records.map((record) => (
<Table.Row key={record.id}>
<Table.Cell>{record.learn_title}</Table.Cell>
<Table.Cell textAlign="center">
<Button onClick={() => onClickDelete(record.id)}>削除</Button>
</Table.Cell>
</Table.Row>
))}
学んだこと
まず、エラーが発生したonClick={関数名(引数)}
の書き方だと、
画面描画時に「関数の実行結果」(ここではPromise<void>型
)がonClick
に渡されてしまいます。
Reactでは、イベントハンドラに渡すべきはMouseEventHandler<HTMLButtonElement>
型、つまり「関数そのもの」です。
戻り値ではなく、クリックイベント時に実行される関数を指定する必要があります。
なぜ無限ループが発生したのか
削除ボタン押下時に関数が実行されるのではなく、画面を表示するタイミングで実行され結果が返っていたため、無限ループなどの予期せぬ事態が発生しました。では、onClick={() => 関数名(引数)}
はどうなのかというと、
「関数そのもの」がonClick
に渡されるため型の不一致が生じず、エラーが解消されるということらしい。
気付き
今までアロー関数とは、コードをシンプルに書けることがメリットとしか考えていませんでした。
今回のケースを通じて、イベントハンドラ設定時に使用することで戻り値の型に違いが生じ、エラーを解消できることを学びました。
参考サイト