이번글을 저번 '이벤트 버블링과 캡처링의 차이'에서 확장된 이벤트 기본동작과 합성 이벤트에 대해서 적어보려고 합니다.
| 요소 | 이벤트 | 동작 |
|---|---|---|
| a태그 | click | 링크이동 |
| form 태그 | submit | 서버로 form 전송 |
| input type='checkbox' | change, click | 체크/언체크 |
| input type='text' | input, change, focus, keydown, keyup, click 등 | 텍스트 입력, 커서 깜빡임 |
| button type="submit" | click | 폼전송 |
| 드래그 동작 | mousedown, mousemove, mouseup, selectstart | 텍스트 선택 |
1) 실제로 React는 기본 이벤트를 랩핑해서 이를 일관된 형태의 구조로 제공합니다. 그래서 event 타입을 찍어보면, 'SyntheticEvent'라고 보입니다.
2) React는 이벤트 등록을 document에 딱 1번만 등록하여 이벤트 위임하는 형태로 이벤트를 처리 하기 때문에 메모리 부분에서 좋다고 볼 수 있습니다.
" 이벤트 객체(SyntheticEvent)를 재사용하는 기법 "
이벤트 핸들러 안에서 비동기 코드나 setTimeout, Promise.then 등에서
SyntheticEvent 객체를 사용하려고 하면 ❗이미 초기화돼서 접근이 안됨.
function App() {
const handleClick = (e) => {
setTimeout(() => {
console.log(e.type); // ❌ 여기서 오류가 날 수 있음! e는 이미 null 처리됨
}, 100);
};
return <button onClick={handleClick}>Click me</button>;
}
이와 같이 하는 이유는 이벤트가 발생할때마다 새로운 이벤트를 생성하는데 이벤트가 메모리를 많이 잡아 먹음. 그래서 SyntheticEvent 초기화해서 다시 계속 재사용하는 방향으로 메모리 효율을 향상시킵니다. 하지만, React 17부터는 event pooling 방식을 사용하지 않습니다.
이벤트 핸들러의 경우에는 컴포넌트가 다시 렌더링 될때마다 새로 만들어진다. 또 비동기 함수를 사용하면 stale closure문제를 만들 수 있다.
그래서 컴포넌트내에서 간단하게 이벤트를 처리하는게 아니라면, useCallback으로 감싸서 stale 클로져 문제가 발생하지 않도록 하는 것이 좋다.
예전에는 useCallback 대신 useEvent로 해서 항상 최신상태의 event 정보를 가져오는 hook이 제공될거라고 했는데, 현재 React 19 공식문서에는 없다.