[React] 이벤트 처리
개요
React의 이벤트 처리는 HTML의 이벤트 처리와 유사하지만, 몇 가지 차이점이 있습니다. 이벤트 핸들러 이름은 카멜케이스를 사용하고, 함수를 직접 전달합니다.
기본 이벤트 처리
// HTML
// <button onclick="handleClick()">클릭</button>
// React JSX
function App() {
const handleClick = () => {
console.log("버튼 클릭!");
};
return (
// 함수 참조를 전달 (함수 호출이 아님!)
<button onClick={handleClick}>클릭</button>
);
}
onClick={handleClick}← 함수 참조 (매 클릭마다 호출)
onClick={handleClick()}← ❌ 렌더링 즉시 호출됨 (주의!)
클릭 이벤트
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
const [message, setMessage] = useState("");
const handleClick = () => {
setCount(count + 1);
setMessage(`${count + 1}번 클릭했습니다`);
};
// 인라인 함수 (간단한 경우)
const handleReset = () => setCount(0);
return (
<div>
<p>{message || "버튼을 클릭하세요"}</p>
<button onClick={handleClick}>클릭 ({count})</button>
<button onClick={handleReset}>초기화</button>
</div>
);
}
입력 이벤트 (가장 중요)
사용자 입력을 State와 동기화하는 제어 컴포넌트(Controlled Component) 패턴입니다.
import { useState } from "react";
function App() {
const [name, setName] = useState("");
// e = 이벤트 객체, e.target.value = 입력값
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setName(e.target.value);
};
return (
<div>
<input
type="text"
value={name} // State와 연결 (제어 컴포넌트)
onChange={handleChange}
placeholder="이름 입력"
/>
<p>입력: {name}</p>
</div>
);
}
value={name}+onChange= 입력 필드가 항상 State와 동기화
이를 제어 컴포넌트(Controlled Component)라고 합니다.
다양한 입력 타입
import { useState } from "react";
function App() {
const [text, setText] = useState("");
const [number, setNumber] = useState(0);
const [checked, setChecked] = useState(false);
const [selection, setSelection] = useState("apple");
const [memo, setMemo] = useState("");
return (
<div>
{/* 텍스트 입력 */}
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
/>
{/* 숫자 입력 */}
<input
type="number"
value={number}
onChange={(e) => setNumber(Number(e.target.value))}
/>
{/* 체크박스 */}
<input
type="checkbox"
checked={checked}
onChange={(e) => setChecked(e.target.checked)} // .value가 아닌 .checked
/>
{/* 셀렉트 */}
<select
value={selection}
onChange={(e) => setSelection(e.target.value)}
>
<option value="apple">사과</option>
<option value="banana">바나나</option>
</select>
{/* 텍스트 영역 */}
<textarea
value={memo}
onChange={(e) => setMemo(e.target.value)}
/>
</div>
);
}
폼 제출
import { useState } from "react";
interface FormData {
name: string;
email: string;
}
function App() {
const [form, setForm] = useState<FormData>({ name: "", email: "" });
const [submitted, setSubmitted] = useState(false);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target; // name 속성으로 필드 구분
setForm({ ...form, [name]: value });
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault(); // 페이지 새로고침 방지 (필수!)
console.log("제출:", form);
setSubmitted(true);
};
return (
<form onSubmit={handleSubmit}>
<input
name="name" // name 속성으로 handleChange에서 구분
value={form.name}
onChange={handleChange}
placeholder="이름"
/>
<input
name="email"
type="email"
value={form.email}
onChange={handleChange}
placeholder="이메일"
/>
<button type="submit">제출</button>
{submitted && <p>제출 완료!</p>}
</form>
);
}
이벤트 객체
function App() {
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
console.log(e.target); // 이벤트 발생 요소
console.log(e.currentTarget); // 이벤트 핸들러가 달린 요소
console.log(e.clientX, e.clientY); // 마우스 좌표
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
console.log("엔터 입력!");
}
if (e.key === "Escape") {
console.log("ESC 입력!");
}
};
return (
<div>
<button onClick={handleClick}>클릭</button>
<input onKeyDown={handleKeyDown} placeholder="Enter/ESC 눌러보기" />
</div>
);
}
주요 이벤트 목록
| 이벤트 | 타입 | 설명 |
|---|---|---|
onClick |
MouseEvent | 클릭 |
onChange |
ChangeEvent | 입력값 변경 |
onSubmit |
FormEvent | 폼 제출 |
onKeyDown / onKeyUp |
KeyboardEvent | 키 입력 |
onFocus / onBlur |
FocusEvent | 포커스 획득/잃음 |
onMouseEnter / onMouseLeave |
MouseEvent | 마우스 진입/이탈 |
onScroll |
UIEvent | 스크롤 |
이벤트 전파 중단
function Parent() {
return (
<div onClick={() => console.log("부모 클릭")}>
<button
onClick={(e) => {
e.stopPropagation(); // 이벤트 버블링 중단
console.log("자식 클릭만");
}}
>
클릭
</button>
</div>
);
}