第2回
Reactイベントハンドラーの型定義:onClick・onChange・onSubmit
TypeScriptでReactのイベントハンドラーを正しく型定義する方法を解説。onClick・onChange・onSubmit・onKeyDown・フォーム要素ごとの型・カスタムイベントハンドラーのprops定義まで実例付きで説明します。
·10分で読める
イベントハンドラーの型の基本
ReactのイベントはブラウザのネイティブEventではなく、Reactがラップした**合成イベント(SyntheticEvent)**です。TypeScriptでは React.MouseEvent や React.ChangeEvent などの型を使います。
import { type MouseEvent, type ChangeEvent } from 'react'
const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
console.log(e.currentTarget.textContent)
}
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value)
}onClick
// ボタンのクリック
const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
console.log('クリックされた')
}
<button onClick={handleClick}>クリック</button>
// divのクリック
const handleDivClick = (e: MouseEvent<HTMLDivElement>) => {}
// イベントオブジェクトが不要な場合は省略可
<button onClick={() => setCount(c => c + 1)}>+</button>onChange:入力フォームの値を取得
const [value, setValue] = useState('')
// inputのonChange
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value)
}
// textareaのonChange
const handleTextChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
setText(e.target.value)
}
// selectのonChange
const handleSelect = (e: ChangeEvent<HTMLSelectElement>) => {
setSelected(e.target.value)
}<input type="text" value={value} onChange={handleChange} />
<textarea value={text} onChange={handleTextChange} />
<select value={selected} onChange={handleSelect}>
<option value="a">A</option>
<option value="b">B</option>
</select>チェックボックス:value ではなく checked を使う
const [checked, setChecked] = useState(false)
const handleCheckChange = (e: ChangeEvent<HTMLInputElement>) => {
setChecked(e.target.checked) // valueではなくchecked
}
<input type="checkbox" checked={checked} onChange={handleCheckChange} />onSubmit:フォームの送信
import { type FormEvent } from 'react'
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault() // ページリロードを防ぐ
const form = e.currentTarget
const name = (form.elements.namedItem('name') as HTMLInputElement).value
console.log(name)
}
<form onSubmit={handleSubmit}>
<input name="name" type="text" />
<button type="submit">送信</button>
</form>onKeyDown / onKeyUp
import { type KeyboardEvent } from 'react'
const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
handleSubmit()
}
if (e.key === 'Escape') {
handleClose()
}
}
<input onKeyDown={handleKeyDown} />イベントハンドラーをpropsとして渡す
コンポーネントにイベントハンドラーを渡すとき、型を明示します。
// ❌ 型が any になってしまう
type ButtonProps = {
onClick: Function
}
// ✅ 正しい型定義
type ButtonProps = {
onClick: () => void
onChange?: (value: string) => void
onSubmit?: (data: FormData) => void
}
const Button = ({ onClick }: ButtonProps) => (
<button onClick={onClick}>クリック</button>
)MouseEvent と引数を組み合わせる
クリックされた要素のIDなど、追加の引数と組み合わせる場合です。
// ❌ これは型エラー:onClickはMouseEventを受け取るので引数を増やせない
<button onClick={handleDelete(item.id)}>削除</button>
// ✅ アロー関数でラップする
<button onClick={() => handleDelete(item.id)}>削除</button>
// または、data属性を使う
const handleDelete = (e: MouseEvent<HTMLButtonElement>) => {
const id = e.currentTarget.dataset['id']
deleteItem(id)
}
<button onClick={handleDelete} data-id={item.id}>削除</button>カスタムイベントの型:子→親へ値を渡す
// 子コンポーネントが親に値を返すパターン
type SearchBoxProps = {
onSearch: (query: string) => void
}
const SearchBox = ({ onSearch }: SearchBoxProps) => {
const [query, setQuery] = useState('')
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault()
onSearch(query) // 親に値を渡す
}
return (
<form onSubmit={handleSubmit}>
<input value={query} onChange={e => setQuery(e.target.value)} />
<button type="submit">検索</button>
</form>
)
}
// 親コンポーネント
const handleSearch = (query: string) => {
console.log('検索:', query)
}
<SearchBox onSearch={handleSearch} />よく使うイベント型の一覧
| イベント | 型 | 要素例 |
|---|---|---|
| クリック | MouseEvent<T> |
button, div, a |
| 入力値変化 | ChangeEvent<T> |
input, select, textarea |
| フォーム送信 | FormEvent<HTMLFormElement> |
form |
| キー操作 | KeyboardEvent<T> |
input, div |
| フォーカス | FocusEvent<T> |
input, button |
| ドラッグ | DragEvent<T> |
div |
| タッチ | TouchEvent<T> |
div(モバイル) |
まとめ
e.target.valueを使うときはChangeEvent<HTMLInputElement>など要素型を指定する- チェックボックスは
e.target.checked - フォーム送信は必ず
e.preventDefault()を呼ぶ - 引数を追加したいときはアロー関数でラップする
- コンポーネントのpropsとして渡すときは
() => voidや(value: string) => voidの形で型定義する