
<!-- HTML 버전 -->
<button onclick="activateLasers()">
Activate Lasers
</button>
<!-- React 버전 -->
<button onClick={activateLasers}>
Activate Lasers
</button>
React에서 이벤트 핸들러를 등록할 때 두 가지 주요 방법
- 화살표 함수로 이벤트 핸들러 전달:
onKeyDown={(e) => handleInputKeyBoardEvent(e)}- 직접 이벤트 핸들러를 전달:
onKeyDown={handleInputKeyBoardEvent}
- 첫 번째 방법은 화살표 함수 내에서 이벤트 핸들러를 호출한다. 이 경우, 매 호출마다 새로운 함수가 생성되기 때문에 성능 면에서 약간의 오버헤드가 발생할 수 있다. 그러나 이 차이는 작고 미비하며, 대부분의 경우에서는 무시할 수 있을 만큼 작다.
- 두 번째 방법은 함수를 직접 전달한다. 이는 함수를 호출하는 게 아니라 해당 함수의 참조를 전달하는 하게 된다. React는 내부적으로 이벤트 핸들러에 전달된 함수를 알아서 적절히 처리하며, 이 경우에도 이벤트 객체가 제대로 전달된다.
- 따라서 두 가지 방법 모두 동작하며, 주된 차이는 성능 측면에서 매우 미세하고, 일반적으로는 무시할 수 있을 정도이지만, 코드를 더 간결하게 작성하고자 한다면, 두 번째 방법을 사용하는 것이 좋다.
모든 이벤트 핸들러에는 해당 이벤트에 대한 정보를 담고 있는 이벤트(event) 객체(e 또는 event)가 매개변수로 전달된다.
e의 객체 구조 (console.log(event))
event.target의 객체 구조 (console.log(event.target))
event.target.value의 객체 구조 (console.log(event.target.value))
이벤트의 기본 동작을 방지하려면 event.preventDefault를 명시적으로 호출해야 한다.
React는 DOM 이벤트 리스너를 각 개별 DOM 요소에 등록하지 않는다. 대신, 이벤트 위임(Event Delegation)을 사용한다.
브라우저에서 이벤트가 발생하면 리액트는 해당 이벤트를 캡처하고 SyntheticEvent 객체를 생성하며, 이 SyntheticEvent 객체가 컴포넌트의 이벤트 핸들러로 전달된다.
function handleClick(event) {
console.log(event.type); // "click"
}
function App() {
return <button onClick={handleClick}>Click me</button>;
}
button 요소에서 클릭 이벤트가 발생하면 브라우저는 이벤트를 document에 전달한다.
리액트는 document에 등록된 글로벌 이벤트 핸들러를 통해 이벤트를 수신한다.
이후, 리액트는 SyntheticEvent 객체를 생성하고 handleClick에 전달한다.
플랫폼 독립성: 브라우저마다 이벤트 객체의 API가 다를 수 있다. SyntheticEvent는 이를 표준화하여 모든 브라우저에서 동일한 API를 제공한다.
가비지 컬렉션 최적화: SyntheticEvent 객체는 이벤트 핸들러가 실행된 후 자동으로 정리된다. 이는 메모리 사용량을 줄이고 성능을 최적화한다.
이벤트 풀링(Event Pooling): 리액트는 SyntheticEvent 객체를 재활용한다. 이벤트 핸들러가 끝난 후에는 SyntheticEvent의 모든 속성이 초기화된다.
function handleClick(event) {
console.log(event); // SyntheticEvent 객체
}
<button onClick={handleClick}>Click me</button>
onClick={handleClick}는 실제로 리액트가 이벤트를 처리하는 과정에서 다음과 같이 동작한다.<button onClick={(e) => handleClick(e)}>Click me</button>
onChange 이벤트는 input(text, checkbox, radio), select, textarea 요소의 값이 입력되었을 때 발생한다.
onChange 이벤트가 발생하면 e.target.value 를 통해 이벤트 객체에 담겨있는 input 값을 읽어올 수 있다.
onChange는 input의 텍스트가 바뀔 때마다 발생하는 이벤트이다. 이벤트가 발생하면 handleChange 함수가 작동하며, 이벤트 객체에 담긴 input값을 setState를 통해 새로운 `state``로 갱신한다.
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
}
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
</div>
)
};
input의 텍스트가 바뀔 때마다 이벤트가 발생한다.
onClick 이벤트는 사용자가 마우스 버튼을 클랙했을 때 발생한다.
버튼이나 <a> 태그를 통한 링크 이동 등과 같이 주로 사용자의 행동에 따라 애플리케이션이 반응해야 할 때 자주 사용한다.
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
}
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
// 버튼을 클릭하면 input에 입력한 값이 alert 창으로 뜬다.
<button onClick={() => { handleChange(); alert(name) }}>Button</button>
</div>
);
};
하나의 이벤트에서 여러개의 이벤트 함수 동시에 실행하기
- 화살표 함수(
() => {})를 사용하며 함수에는()를 붙여주고 함수마다 세미콜론(;)으로 구분해준다.onClick={() => { handleChange(); alert(name) }}
이벤트 핸들러에 함수를 직접 호출하면 안 되는 이유
일반적으로 이벤트 핸들러에 함수를 직접 호출하는 방식인
onClick={getSelectDetailData(word)}를 사용하면 안 되는 이유는 아래와 같다.
onClick={getSelectDetailData(word)}라고 작성하면 페이지가 렌더링될 때getSelectDetailData(word)가 즉시 실행된다. 즉, 이벤트 핸들러로 할당되는 것이 함수의 반환 값이 아니라, 함수 호출 자체가 된다. 원하는 것은 클릭 이벤트가 발생했을 때 함수를 실행해야 하는데, 이렇게 작성하면 페이지가 로드될 때 함수가 즉시 실행되어 원하는 시점에 실행되지 않고 초기 렌더링 시에만 실행되게 된다.그러나
onClick={() => getSelectDetailData(word)}와 같이 화살표 함수를 사용하면 화살표 함수 내에서getSelectDetailData(word)를 호출하므로 클릭 이벤트가 발생했을 때 함수가 실행된다.
이벤트 핸들러에 함수 호출을 바로 전달하는 것보다 화살표 함수를 사용하여 해당 함수를 호출하면, 이벤트가 발생했을 때 함수가 실행되도록 보장할 수 있다.
모든 키를 눌렀을 때 발생한다.
onKeyDown 이벤트와 마찬가지로 control, option, shift, tab, delete, enter, 방향 키와 문자, 숫자, 특수 문자 키를 놓았을 때 발생한다. 단, 문자, 숫자, 특수 문자, enter키를 눌렀을 때는 연속적으로 발생하지만 그 외의 키를 눌렀을 때는 한 번만 발생한다.
onKeyUp 이벤트는 누르고 있던 키를 놓았을 때 한 번만 발생한다.
onKeyDown 이벤트와 마찬가지로 control, option, shift, tab, delete, enter, 방향 키와 문자, 숫자, 특수 문자 키를 놓았을 때 발생한다.
한글 입력 후 Enter키 입력 시 중복으로 입력되는 현상
- 영어가 아닌 한글 입력 후 Enter키 입력 시 중복으로 이벤트가 실행되는 현상이 발생하는데 이 경우 조건식에
event.nativeEvent.isComposing === false를 추가해준다.const handleKeyupTodoText = (event) => { if (event.key === 'Enter' && event.nativeEvent.isComposing === false) { addTodoText(); } };
- 이벤트가 중복 실행되는 에러