React 이벤트 핸들링 — 합성 이벤트와 패턴
onClick·onChange 가 어떻게 작동하는지, 인자 전달은 어떻게, 그리고 흔한 함정.
4편에서 onClick 기본 패턴을 짧게 봤다. 이번 7편은 본격적으로 — React 가 왜 합성 이벤트 (SyntheticEvent) 시스템을 따로 만들었는지, preventDefault·stopPropagation 사용법, 핸들러에 인자를 깨끗이 넘기는 4가지 패턴까지.
1. 합성 이벤트 — DOM 이벤트의 wrapper
React 의 onClick·onChange 가 호출하는 함수에 들어오는 첫 인자는 SyntheticEvent — 브라우저 native 이벤트를 React 가 한 번 감싼 객체.
왜 wrapper 인가 — 브라우저 호환성. IE·Safari·Chrome 의 이벤트 차이를 React 가 흡수해 모든 브라우저에서 같은 API. 2026 년엔 IE 가 죽었지만 모바일 브라우저 미묘한 차이는 여전. 또 React 18 부터는 root 단일 listener + 이벤트 위임으로 메모리 효율도 잡았다.
React.ChangeEvent<HTMLInputElement> · React.MouseEvent<HTMLButtonElement> 식으로 명시. IDE 자동완성이 강력. e.target.value 가 string 인지 number 인지도 정확히 알려준다.
2. preventDefault · stopPropagation — 가장 자주 쓰는 두 메서드
두 가지 — preventDefault (브라우저 기본 동작 막기) 와 stopPropagation (부모 이벤트로 전파 막기). 5편 차이.
실전 빈도 — preventDefault 가 압도적으로 많다. form 제출, anchor 태그 동작 차단, drag 기본 동작 등. stopPropagation 은 모달 외부 클릭 닫기 같은 특수 케이스.
3. 인자 전달 — 4가지 패턴
핸들러에 추가 정보 (item ID 등) 를 넘기는 방법. 4편에서 인라인 화살표 패턴을 봤지만 옵션이 더 있다.
실전 선택 — 항목 수가 적으면 패턴 1, 수백 개 이상이면 패턴 2 (인라인 함수가 매 렌더마다 새 함수 객체 생성 → 자식 memo 가 깨짐. 16편에서 다시 등장). 패턴 4 가 가독성·재사용 둘 다 우위.
4. 흔한 함정 — 핸들러 안에서 state 옛 값
6편에서 봤듯 setter 는 비동기. 이벤트 핸들러 안에서 같은 state 를 여러 번 갱신할 때 자주 어긋난다.
onClick 이 async 함수라면, await 후의 코드에서도 count 는 클릭 시점의 옛 값. setCount(prev => prev + 1) 함수형 패턴이나 useRef 로 최신 값 추적 필요. 11편 useEffect 의 closure 함정과 같은 뿌리.
이벤트 핸들링이 손에 잡히면 React 의 "사용자 액션 → state 변경 → UI 재렌더" 사이클이 완성된다. 8편에서는 그 state 가 다양해질 때 UI 를 조건부로 그리는 패턴으로 들어간다.
다음 글
React 교재 8편 — 조건부 렌더링. 삼항 · && · null 반환 + 0 표시 함정 + early return.