React 독학 가이드 8 - Event Handling 완벽 가이드
웹사이트에서 버튼 클릭하면 뭔가 동작하잖아요. 입력창에 글 쓰면 실시간으로 반응하고요. 이런 걸 이벤트 처리라고 해요. React에서 이벤트 다루는 법을 알아볼게요.
HTML vs React 이벤트 차이점
HTML에서 이벤트 처리하던 방식이랑 약간 달라요.
<!-- HTML 방식 -->
<button onclick="handleClick()">클릭</button>
// React 방식
<button onClick={handleClick}>클릭</button>
차이점 3가지:
- 이벤트명이 카멜케이스 (onclick → onClick)
- 함수를 문자열이 아닌 중괄호로 전달
- 함수를 호출하지 않고 전달 (handleClick() ❌ → handleClick ⭕)
onClick - 클릭 이벤트
가장 많이 쓰는 이벤트예요.
기본 사용법
function App() {
const handleClick = () => {
alert("버튼을 클릭했습니다!");
};
return <button onClick={handleClick}>클릭하세요</button>;
}
인라인으로 쓰기
간단한 동작은 바로 써도 돼요:
<button onClick={() => alert("클릭!")}>클릭</button>
주의: 함수 호출하면 안 됨
// ❌ 잘못된 방법 - 렌더링할 때 바로 실행됨!
<button onClick={handleClick()}>클릭</button>
// ⭕ 올바른 방법
<button onClick={handleClick}>클릭</button>
handleClick()처럼 괄호를 붙이면 컴포넌트가 렌더링될 때 바로 실행돼버려요.
매개변수 전달하기
함수에 값을 넘기고 싶으면 화살표 함수로 감싸세요:
function App() {
const handleClick = (name) => {
alert(`${name}님, 안녕하세요!`);
};
return (
<div>
<button onClick={() => handleClick("홍길동")}>홍길동</button>
<button onClick={() => handleClick("김철수")}>김철수</button>
</div>
);
}
이벤트 객체 (event)
이벤트 핸들러는 자동으로 이벤트 객체를 받아요:
function App() {
const handleClick = (e) => {
console.log(e); // 이벤트 객체
console.log(e.target); // 클릭된 요소
console.log(e.type); // 이벤트 타입 ("click")
};
return <button onClick={handleClick}>클릭</button>;
}
매개변수와 이벤트 객체 둘 다 받기
const handleClick = (id, e) => {
console.log("ID:", id);
console.log("이벤트:", e);
};
<button onClick={(e) => handleClick(123, e)}>클릭</button>
onChange - 입력 이벤트
입력창에서 값이 바뀔 때 발생해요:
function App() {
const handleChange = (e) => {
console.log(e.target.value); // 입력된 값
};
return <input type="text" onChange={handleChange} />;
}
실시간 입력 표시
import { useState } from 'react';
function App() {
const [text, setText] = useState("");
const handleChange = (e) => {
setText(e.target.value);
};
return (
<div>
<input type="text" onChange={handleChange} />
<p>입력값: {text}</p>
</div>
);
}
입력할 때마다 바로 밑에 보여요!
onSubmit - 폼 제출
폼 제출할 때 발생하는 이벤트예요:
function LoginForm() {
const handleSubmit = (e) => {
e.preventDefault(); // 페이지 새로고침 방지!
console.log("폼 제출됨");
};
return (
<form onSubmit={handleSubmit}>
<input type="text" placeholder="아이디" />
<input type="password" placeholder="비밀번호" />
<button type="submit">로그인</button>
</form>
);
}
e.preventDefault()가 중요해요! 안 쓰면 폼 제출하자마자 페이지가 새로고침돼요.
자주 쓰는 이벤트 목록
마우스 이벤트
<button onClick={handleClick}>클릭</button>
<button onDoubleClick={handleDoubleClick}>더블클릭</button>
<div onMouseEnter={handleEnter}>마우스 올리면</div>
<div onMouseLeave={handleLeave}>마우스 나가면</div>
<div onMouseMove={handleMove}>마우스 움직이면</div>
키보드 이벤트
<input onKeyDown={handleKeyDown} /> // 키 누를 때
<input onKeyUp={handleKeyUp} /> // 키 뗄 때
<input onKeyPress={handleKeyPress} /> // 글자 입력될 때 (deprecated)
function App() {
const handleKeyDown = (e) => {
if (e.key === "Enter") {
console.log("엔터 눌림!");
}
if (e.key === "Escape") {
console.log("ESC 눌림!");
}
};
return <input onKeyDown={handleKeyDown} />;
}
포커스 이벤트
<input onFocus={handleFocus} /> // 포커스 받을 때
<input onBlur={handleBlur} /> // 포커스 잃을 때
function App() {
const handleFocus = () => {
console.log("입력창 선택됨");
};
const handleBlur = () => {
console.log("입력창에서 나감");
};
return (
<input
onFocus={handleFocus}
onBlur={handleBlur}
placeholder="클릭해보세요"
/>
);
}
실전 예제: 카운터 앱
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increase = () => setCount(count + 1);
const decrease = () => setCount(count - 1);
const reset = () => setCount(0);
return (
<div style={{ textAlign: 'center', padding: '20px' }}>
<h1>{count}</h1>
<button onClick={decrease}>-</button>
<button onClick={reset}>리셋</button>
<button onClick={increase}>+</button>
</div>
);
}
실행 결과:
7
버튼 클릭 이벤트로 카운터를 조작할 수 있습니다
실전 예제: 검색창
import { useState } from 'react';
function SearchBox() {
const [query, setQuery] = useState("");
const [results, setResults] = useState([]);
const fruits = ["사과", "바나나", "오렌지", "포도", "수박", "딸기"];
const handleChange = (e) => {
const value = e.target.value;
setQuery(value);
if (value.trim()) {
const filtered = fruits.filter((fruit) =>
fruit.includes(value)
);
setResults(filtered);
} else {
setResults([]);
}
};
return (
<div>
<input
type="text"
value={query}
onChange={handleChange}
placeholder="과일 검색..."
style={{ padding: '10px', width: '200px' }}
/>
<ul>
{results.map((fruit) => (
<li key={fruit}>{fruit}</li>
))}
</ul>
</div>
);
}
실시간으로 검색 결과가 필터링돼요!
실전 예제: 할 일 추가하기
import { useState } from 'react';
function TodoApp() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
if (!input.trim()) return;
setTodos([...todos, { id: Date.now(), text: input }]);
setInput(""); // 입력창 비우기
};
const handleDelete = (id) => {
setTodos(todos.filter((todo) => todo.id !== id));
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="할 일 입력..."
/>
<button type="submit">추가</button>
</form>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
{todo.text}
<button onClick={() => handleDelete(todo.id)}>삭제</button>
</li>
))}
</ul>
</div>
);
}
이벤트 버블링과 stopPropagation
클릭 이벤트는 부모까지 전파돼요(버블링):
function App() {
const handleParent = () => console.log("부모 클릭");
const handleChild = () => console.log("자식 클릭");
return (
<div onClick={handleParent} style={{ padding: '50px', background: '#ddd' }}>
<button onClick={handleChild}>클릭</button>
</div>
);
}
// 버튼 클릭 시: "자식 클릭" -> "부모 클릭" 둘 다 출력됨
전파를 막으려면:
const handleChild = (e) => {
e.stopPropagation(); // 부모로 이벤트 전파 막기
console.log("자식 클릭");
};
이벤트 핸들러 네이밍 컨벤션
// 이벤트 핸들러 이름은 handle + 동작으로
const handleClick = () => {};
const handleSubmit = () => {};
const handleChange = () => {};
const handleInputChange = () => {}; // 더 구체적으로
// Props로 전달할 때는 on + 동작으로
<Button onClick={handleClick} />
<Form onSubmit={handleSubmit} />
<Input onChange={handleChange} />
다음 단계
이벤트 처리를 배웠으니, 다음 글에서는 State를 본격적으로 다뤄볼 거예요. 여기서 useState를 잠깐 썼는데, 다음 글에서 제대로 배워봅시다.
이벤트랑 State를 같이 쓰면 진짜 동적인 앱을 만들 수 있어요. 기대하세요!
React 시리즈 탐색:
← 블로그 목록으로