사용자의 행동(클릭, 입력, 마우스 이동 등)에 반응하는 인터랙티브한 웹사이트를 만들기 위해 React의 이벤트 시스템을 깊이 있게 학습한다.
이벤트(Event)는 사용자가 웹페이지에서 취하는 행동을 의미한다. 버튼 클릭, 키보드 입력, 마우스 이동 등 모든 상호작용이 이벤트다.
| 구분 | HTML | React |
|---|---|---|
| 이벤트명 | 소문자onclick |
카멜케이스onClick |
| 핸들러 | 문자열"handleClick()" |
함수{handleClick} |
| 기본 동작 방지 | return false |
e.preventDefault() |
// HTML 방식
<button onclick="handleClick()">클릭</button>
// React 방식
<button onClick={handleClick}>클릭</button>
onClick: 요소를 클릭했을 때onDoubleClick: 요소를 더블클릭했을 때onMouseEnter: 마우스가 요소 위로 들어왔을 때onMouseLeave: 마우스가 요소를 벗어났을 때onKeyDown: 키를 누르는 순간onKeyUp: 키를 뗀 순간onChange: 입력값이 변경될 때onSubmit: 폼이 제출될 때onFocus: 요소에 포커스가 갔을 때onBlur: 요소에서 포커스가 벗어났을 때onClick={handleClick()} ❌ 잘못됨!onClick={handleClick} ✅ 올바름!function Button() {
const handleClick = () => {
console.log("클릭됨");
};
return (
<div>
{/* ❌ 렌더링 시 즉시 실행 */}
<button onClick={handleClick()}>잘못된 예</button>
{/* ✅ 클릭 시에만 실행 */}
<button onClick={handleClick}>올바른 예</button>
{/* ✅ 화살표 함수로 감싸면 OK */}
<button onClick={() => handleClick()}>이것도 OK</button>
</div>
);
}
function ClickExample() {
const handleClick = () => {
alert("클릭됨");
};
const handleClick2 = () => {
console.log("두 번째 버튼");
};
return (
<div>
<button onClick={handleClick}>버튼 1</button>
<button onClick={handleClick2}>버튼 2</button>
<button onClick={() => alert("버튼 3")}>버튼 3</button>
</div>
);
}
function ButtonList() {
const handleClick = (name) => {
alert(`${name} 클릭됨`);
};
return (
<div>
{/* ❌ 잘못됨 */}
<button onClick={handleClick("빨강")}>빨강</button>
{/* ✅ 올바름 */}
<button onClick={() => handleClick("빨강")}>빨강</button>
<button onClick={() => handleClick("파랑")}>파랑</button>
</div>
);
}
function InteractiveButtons() {
const handleDoubleClick = () => {
alert("더블클릭");
};
const handleMouseEnter = () => {
console.log("마우스 진입");
};
const handleContextMenu = (e) => {
e.preventDefault();
alert("우클릭 금지");
};
return (
<div>
<button onDoubleClick={handleDoubleClick}>더블클릭</button>
<div onMouseEnter={handleMouseEnter} className="hover-box">
마우스 올리기
</div>
<div onContextMenu={handleContextMenu}>우클릭 방지</div>
</div>
);
}
function KeyboardExample() {
const handleKeyDown = (e) => {
console.log(`눌린 키: ${e.key}`);
console.log(`키코드: ${e.keyCode}`);
};
const handleEnter = (e) => {
if (e.key === 'Enter') {
alert("엔터 눌림");
}
};
return (
<div>
<input
type="text"
onKeyDown={handleKeyDown}
placeholder="키를 눌러보세요"
/>
<input
type="text"
onKeyDown={handleEnter}
placeholder="엔터를 눌러보세요"
/>
</div>
);
}
function KeyCombo() {
const handleKeyDown = (e) => {
if (e.ctrlKey && e.key === 's') {
e.preventDefault();
console.log("Ctrl+S 눌림");
}
if (e.shiftKey && e.key === 'Enter') {
console.log("Shift+Enter 눌림");
}
};
return (
<textarea
onKeyDown={handleKeyDown}
placeholder="Ctrl+S 또는 Shift+Enter 눌러보기"
/>
);
}
function InputExample() {
const handleChange = (e) => {
console.log("입력값:", e.target.value);
};
return (
<div>
<input
type="text"
onChange={handleChange}
placeholder="입력하세요"
/>
</div>
);
}
function FormExample() {
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = Object.fromEntries(formData);
console.log("제출 데이터:", data);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" name="username" placeholder="이름" />
<input type="email" name="email" placeholder="이메일" />
<button type="submit">제출</button>
</form>
);
}
function ValidationForm() {
const handleUsernameChange = (e) => {
const val = e.target.value;
if (val.length < 3) {
console.log("아이디는 3자 이상");
}
};
const handleEmailChange = (e) => {
const val = e.target.value;
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!regex.test(val)) {
console.log("이메일 형식 오류");
}
};
const handlePasswordChange = (e) => {
const val = e.target.value;
const regex = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/;
if (!regex.test(val)) {
console.log("비밀번호: 8자 이상, 문자+숫자+특수문자");
}
};
return (
<form>
<input
type="text"
onChange={handleUsernameChange}
placeholder="아이디"
/>
<input
type="email"
onChange={handleEmailChange}
placeholder="이메일"
/>
<input
type="password"
onChange={handlePasswordChange}
placeholder="비밀번호"
/>
</form>
);
}
function FocusExample() {
const handleFocus = (e) => {
e.target.className = 'focused';
};
const handleBlur = (e) => {
e.target.className = '';
if (e.target.required && !e.target.value) {
e.target.className = 'error';
}
};
return (
<div>
<input
type="text"
onFocus={handleFocus}
onBlur={handleBlur}
placeholder="포커스 테스트"
/>
</div>
);
}
function SignupForm() {
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = Object.fromEntries(formData);
console.log("회원가입 데이터:", data);
alert("가입 완료");
};
const handleUsernameChange = (e) => {
const val = e.target.value;
if (val.length < 3 || val.length > 20) {
console.log("아이디: 3-20자");
}
};
const handleEmailChange = (e) => {
const val = e.target.value;
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!regex.test(val)) {
console.log("이메일 형식 오류");
}
};
const handlePasswordChange = (e) => {
const val = e.target.value;
const regex = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/;
if (!regex.test(val)) {
console.log("비밀번호: 8자 이상, 문자+숫자+특수문자");
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>아이디 *</label>
<input
type="text"
name="username"
required
onChange={handleUsernameChange}
placeholder="3-20자"
/>
</div>
<div>
<label>이메일 *</label>
<input
type="email"
name="email"
required
onChange={handleEmailChange}
placeholder="example@mail.com"
/>
</div>
<div>
<label>비밀번호 *</label>
<input
type="password"
name="password"
required
onChange={handlePasswordChange}
placeholder="8자 이상"
/>
</div>
<div>
<label>나이</label>
<input
type="number"
name="age"
min="1"
max="150"
/>
</div>
<div>
<label>성별</label>
<label>
<input type="radio" name="gender" value="male" /> 남성
</label>
<label>
<input type="radio" name="gender" value="female" /> 여성
</label>
</div>
<div>
<label>
<input type="checkbox" name="agree" required />
이용약관 동의 *
</label>
</div>
<button type="submit">회원가입</button>
</form>
);
}
| 이벤트 | 용도 | 주의사항 |
|---|---|---|
onClick |
클릭 처리 | 함수 전달 시 괄호 금지 |
onChange |
입력값 변경 | 실시간 발생 |
onSubmit |
폼 제출 | preventDefault 필수 |
onKeyDown |
키보드 입력 | e.key로 확인 |
onFocus/Blur |
포커스 관리 | 유효성 검사 타이밍 |
useState를 학습하여 화면을 동적으로 변경하는 방법을 배운다.