
이벤트에 응답하기
이벤트 핸들러는 클릭, 마우스 호버, 폼 입력, 포커스 등
사용자 상호작용에 반응해 실행되는 사용자 정의 함수이다.
React에서는 JSX에 함수를 전달하는 방식으로 이벤트를 처리한다.
이벤트 핸들러 추가하기
export default function Button() {
function handleClick() {
alert("You clicked me");
}
return <button onClick={handleClick}>I don't do anything</button>;
}
위 코드에서 handleClick은 이벤트 핸들러이다.
이벤트 핸들러의 특징 ✍️
- 보통 컴포넌트 내부에서 정의된다
- handle로 시작하고 이벤트 이름을 뒤에 붙이는 경우가 많다
- JSX에는 호출이 아니라 전달한다
onClick={handleClick} // ✅
onClick={handleClick()} // ❌
이벤트 핸들러 내에서 props 읽기
function AlertButton({ message, children }) {
return <button onClick={() => alert(message)}>{children}</button>;
}
이벤트 핸들러는 컴포넌트 내부에 정의되기 때문에
props와 state에 자유롭게 접근할 수 있었다.
렌더링 중에 실행되지 않기 때문에 순수할 필요도 없었다.
이벤트 핸들러를 props로 전달하기
function Button({ onClick, children }) {
return <button onClick={onClick}>{children}</button>;
}
이 방식은 재사용 가능한 버튼 컴포넌트를 만들 때 유용했다.
function PlayButton({ movieName }) {
function handlePlayClick() {
alert(`Playing ${movieName}!`);
}
return <Button onClick={handlePlayClick}>Play "{movieName}"</Button>;
}
이벤트 핸들러 prop 명명하기
function Button({ onSmash, children }) {
return <button onClick={onSmash}>{children}</button>;
}
export default function App() {
return (
<div>
<Button onSmash={() => alert("Playing!")}>Play Movie</Button>
<Button onSmash={() => alert("Uploading!")}>Upload Image</Button>
</div>
);
}
이벤트 핸들러 prop은 on으로 시작하는 이름을 사용할 수 있다.
하지만 이 경우 문제가 있었다.
- onSmash라는 이름은 버튼의 의미를 고정시킨다
- 재사용성이 떨어진다 ❌
더 나은 구조: 관심사 분리
function Button({ onClick, children }) {
return <button onClick={onClick}>{children}</button>;
}
function Toolbar({ onPlayMovie, onUploadImage }) {
return (
<div>
<Button onClick={onPlayMovie}>Play Movie</Button>
<Button onClick={onUploadImage}>Upload Image</Button>
</div>
);
}
export default function App() {
return (
<Toolbar
onPlayMovie={() => alert("Playing!")}
onUploadImage={() => alert("Uploading!")}
/>
);
}
역할 분리 정리 ✍️
- Button
- 순수 UI 컴포넌트
- 클릭되면 onClick 호출만 함
- Toolbar
- 버튼의 “의미”를 정의함
- App
- 실제 비즈니스 로직 담당
이 구조는 재사용성, 테스트, 유지보수 측면에서 훨씬 안정적이었다.
이벤트 전파
<div onClick={() => alert("Toolbar clicked")}>
<button onClick={() => alert("Playing")}>Play</button>
</div>
버튼을 클릭하면:
- 버튼의 onClick 실행
- 이후 부모 요소의 onClick 실행
React의 이벤트는 기본적으로 **위쪽으로 전파(bubbling)**된다.
(onScroll을 제외한 대부분의 이벤트가 해당된다)
전파 멈추기
<button
onClick={(e) => {
e.stopPropagation();
onClick();
}}
>
{children}
</button>
e.stopPropagation()을 호출하면 이벤트 전파를 멈출 수 있다.
버튼 클릭은 툴바 클릭과 의미가 다르기 때문에,
이 경우 전파를 막는 것이 UI적으로 합리적이었다.
기본 동작 방지하기
<form
onSubmit={(e) => {
e.preventDefault();
alert("Submitting!");
}}
>
- <form>의 기본 동작은 페이지 리로드이다
- 이를 막기 위해 e.preventDefault()를 사용했다
둘은 다르다 ❗
- e.stopPropagation()
→ 이벤트 전파 중단 - e.preventDefault()
→ 브라우저 기본 동작 중단
이벤트 핸들러와 사이드 이펙트
이벤트 핸들러는 사이드 이펙트를 처리하기에 가장 적절한 위치였다.
- 상태 변경
- 알림 표시
- DOM 조작
렌더링과 달리 순수할 필요가 없기 때문이다.
🧩 챌린지 1 of 2 : 이벤트 핸들러 고치기
문제 코드
<button onClick={handleClick()}>
Toggle the lights
</button>
이벤트 핸들러를 호출하고 있었기 때문에
렌더링 시점에 실행되어 클릭 시 아무 일도 일어나지 않았다.
정답 코드
<button onClick={handleClick}>
Toggle the lights
</button>
정리 ✍️
이벤트 핸들러는 전달만 해야 하며,
React가 필요할 때 호출하도록 맡겨야 한다.
✍️ 요약
- 이벤트 핸들러는 JSX에 함수 참조로 전달한다
- 이벤트 핸들러는 컴포넌트 내부에서 정의할 수 있다
- 이벤트 핸들러는 props로 내려 재사용할 수 있다
- 의미는 부모가 정의하고, UI는 자식이 담당하는 구조가 좋았다
- 이벤트는 기본적으로 전파된다
- stopPropagation과 preventDefault는 역할이 다르다
- 이벤트 핸들러는 사이드 이펙트를 처리하기에 가장 적절한 위치였다
728x90
반응형
'Frontend > React' 카테고리의 다른 글
| [React] 리스트 렌더링과 key의 역할 정리 (0) | 2026.02.05 |
|---|---|
| [React] 조건부 렌더링 제대로 정리하기 (if, ? :, &&, null) (1) | 2026.02.04 |
| Tanstack Query 캐싱 메커니즘 이해하기 (1) | 2026.01.20 |
| Zustand 미들웨어를 정리하며: immer, subscribeWithSelector, persist, devtools (0) | 2025.12.17 |
| Zustand combine 미들웨어, 처음엔 안 와닿았던 이유 (0) | 2025.12.15 |