onClick, onChange, onSubmit 등 주요 이벤트 핸들러 등록 방법과 이벤트 객체 활용, 그리고 이벤트 버블링 이해까지 실전 중심으로 배웁니다.
🖱️ 이벤트 처리 — 리액트 방식
리액트에서 이벤트를 처리하는 방법은 HTML과 비슷하지만 몇 가지 중요한 차이가 있습니다. 가장 큰 차이는 이벤트 핸들러를 함수 참조로 전달한다는 점입니다.
// ❌ HTML 방식 — 문자열로 함수 호출
<button onclick="handleClick()">클릭</button>
// ✅ 리액트 방식 — 함수 참조 전달
<button onClick={handleClick}>클릭</button>
// ✅ 인라인 화살표 함수
<button onClick={() => console.log('클릭!')}>클릭</button>
리액트의 이벤트 속성은 카멜케이스입니다: onclick → onClick, onchange → onChange, onsubmit → onSubmit.
📋 주요 이벤트 핸들러 목록
| 이벤트 | JSX 속성 | 발생 시점 |
|---|---|---|
| 마우스 클릭 | onClick | 요소 클릭 |
| 입력 변경 | onChange | input/textarea 값 변경 |
| 폼 제출 | onSubmit | form 제출 |
| 키 누름 | onKeyDown, onKeyUp | 키보드 입력 |
| 마우스 진입 | onMouseEnter, onMouseLeave | 마우스 오버 |
| 포커스 | onFocus, onBlur | 입력 요소 포커스 변경 |
⚙️ 이벤트 객체 활용하기
이벤트 핸들러는 자동으로 이벤트 객체(event object)를 첫 번째 인수로 받습니다. 이 객체에는 이벤트에 대한 정보가 담겨있습니다.
function SearchBar() {
const [query, setQuery] = useState('')
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
setQuery(e.target.value) // e.target.value로 현재 입력값 접근
console.log('입력값:', e.target.value)
}
function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
if (e.key === 'Enter') { // 엔터 키 감지
console.log('검색:', query)
}
if (e.key === 'Escape') {
setQuery('')
}
}
return (
<input
type="text"
value={query}
onChange={handleChange}
onKeyDown={handleKeyDown}
placeholder="검색어 입력..."
/>
)
}
TypeScript를 사용할 때 이벤트 타입을 명시하면 자동완성이 작동합니다: React.ChangeEvent<HTMLInputElement>, React.MouseEvent<HTMLButtonElement> 등.
🚫 이벤트 기본 동작 방지 — preventDefault
폼 제출 시 페이지가 새로고침되는 것처럼, HTML 이벤트는 기본 동작이 있습니다. e.preventDefault()로 이를 막을 수 있습니다.
function LoginForm() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault() // ← 페이지 새로고침 방지
console.log('로그인 시도:', email, password)
// 여기서 API 호출
}
return (
<form onSubmit={handleSubmit}>
<input value={email} onChange={(e) => setEmail(e.target.value)} type="email" />
<input value={password} onChange={(e) => setPassword(e.target.value)} type="password" />
<button type="submit">로그인</button>
</form>
)
}
🫧 이벤트 버블링과 stopPropagation
이벤트 버블링이란 자식 요소에서 발생한 이벤트가 부모 요소로 전파(bubble up)되는 현상입니다. 카드 내부 버튼 클릭 시 카드 전체의 클릭 이벤트도 발생하는 문제가 생깁니다.
function PostCard() {
function handleCardClick() {
console.log('카드 클릭 — 상세 페이지로 이동')
}
function handleDeleteClick(e: React.MouseEvent) {
e.stopPropagation() // ← 부모로 이벤트 전파 차단
console.log('삭제 버튼 클릭 — 카드 클릭은 발생 안 함')
}
return (
<div onClick={handleCardClick} className="card">
<h3>게시글 제목</h3>
<button onClick={handleDeleteClick}>삭제</button> {/* 클릭해도 카드 이동 안 됨 */}
</div>
)
}
🔧 핸들러에 인수 전달하기
이벤트 핸들러에 추가 인수를 전달하고 싶을 때는 화살표 함수로 감쌉니다:
type Item = { id: number; name: string }
function ItemList({ items }: { items: Item[] }) {
function handleDelete(id: number) {
console.log('삭제:', id)
}
return (
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name}
{/* 화살표 함수로 감싸 id를 전달 */}
<button onClick={() => handleDelete(item.id)}>삭제</button>
</li>
))}
</ul>
)
}
주의: onClick={handleDelete(item.id)}처럼 함수를 바로 호출하면 안 됩니다. 렌더링 중에 즉시 실행됩니다.
✅ 정리
- 리액트 이벤트 속성은 카멜케이스:
onClick,onChange,onSubmit. - 이벤트 핸들러는 함수를 참조로 전달합니다 (
{handleClick},{() => doSomething()}). e.preventDefault()로 기본 동작(폼 제출, 링크 이동)을 막습니다.e.stopPropagation()으로 이벤트가 부모로 전파되는 것을 막습니다.- 추가 인수를 전달할 때는 화살표 함수로 감쌉니다:
onClick={() => handler(id)}.
관련 주제
- onClick onChange onSubmit
- 이벤트 핸들러 함수 참조
- 카멜케이스 이벤트 속성
- 이벤트 객체
- 인라인 vs 함수 분리
- 개발·프로그래밍
- 개발·프로그래밍 강의
- 리액트 입문 — 컴포넌트로 만드는 웹
- 무료강의
- 무료 온라인 강의
- NUGUNA
- 누구나
