사용자가 웹 브라우저에서 DOM 요소들과 상호작용하는 것을 이벤트라고 한다. 예를 들어 버튼에 커서를 올렸을 때는 onmouseover
이벤트, 클릭했을 때는 onclick
, 폼 요소는 값일 바뀔 때 onchange
이벤트를 실행한다. 이벤트 종류는 여기 참고
<button onClick={실행 함수명}>버튼</button>
이벤트를 사용할 때 주의 사항
div, button, input, form, span
등의 요소가 아닌 직접 만든 컴포넌트에는 이벤트를 자체적으로 설정할 수 없다. 예를 들어, MyComponent
에 onClick
값을 설정한다면 onClick
인 props
가 전달될 뿐이다. 하지만 이를 컴포넌트 내부에서 전달받아 DOM 이벤트로 설정하면 된다.<MyComponent onClick={doSomethig}/>
// MyComponent 내부
<div onClick={this.props.onClick}>
{/*...*/}
</div>
import React, { Component } from 'react';
class EventPractice extends Component {
render() {
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="message"
placeholder="아무거나 입력해 보세요"
onChange={
(e) => {
console.log(e);
}
}
/>
</div>
);
}
}
export default EventPractice;
코드를 저장하고 웹브라우저에서 크롬 개발자 도구를 열어 인풋에 아무것이나 입력하면 이벤트 객체가 console.log
되는 것을 확인할 수 있다. 여기서 이벤트 객체는 SyntheticEvent
로 웹 브라우저의 네이티브 이벤트를 감싸는 객체이다.
SyntheticEvent
는 네이티브 이벤트와 달리 이벤트가 끝나고 나면 이벤트가 초기화되므로 정보를 참조할 수 없다. 예를 들어, 0.5초 뒤에 e 객체를 참조하면 e 객체 내부의 모든 값이 비워지게 된다.
만약 비동기적으로 이벤트 객체를 참조할 일이 있다면, e.persist()
함수를 호출해 주어야 한다. 예를 들어 onChange
이벤트가 발생할 때, 앞으로 변할 인풋 값인 e.target.value
를 콘솔에 기록하면 된다. 아래처럼 코드를 수정하면 값이 바뀜에 따라 콘솔에 바로바로 기록되는 것을 확인할 수 있다.
onChange={
(e) => {
console.log(e.target.value);
}
}
이번에는 state에 input 값을 넣어 볼 것이다. 아래 코드와 같이 이벤트 핸들링 함수 내부에서 this.setState
메서드를 호출하여 state
를 업데이트한다. 그 다음에는 input
의 value
값을 state
에 있는 값으로 설정하면 된다.
정말로 입력한 값이 state
에 잘 들어갔는지, 그리고 input
에서 그 값을 제대로 반영하는지 검증하기 위해 input
요소 코드 아래쪽에 button
을 하나 만들고, 클릭 이벤트가 발생하면 현재 comment
값을 메시지 박스로 띄운 후 comment
값을 공백으로 설정했다.
import React, { Component } from 'react';
class EventPractice extends Component {
state = {
message: ''
}
render() {
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="message"
placeholder="아무거나 입력해 보세요"
value={this.state.message}
onChange={
(e) => {
this.setState({
message: e.target.value
})
}
}
/>
<button onClick={
() => {
alert(this.state.message);
this.setState({
message:''
});
}
}>확인</button>
</div>
);
}
}
export default EventPractice;
위 코드는 임의 메소드를 정의함으로써 가독성을 높일 수 있다. 기본 방식으로 한다면 constructor
함수 내에서 바인딩이 이루어져야 하지만 바벨의 transform-class-properties
문법을 사용하여 화살표 함수 형태로 메서드를 정의하면 더 간단히 구현할 수 있다. 웬만하면 이벤트 핸들링 메소드는 handle~
형식으로 네이밍 한다.
import React, { Component } from 'react';
class EventPractice extends Component {
state = {
message: ''
}
handleChange = (e) => {
this.setState({
message: e.target.value
});
}
handleClick = () => {
alert(this.state.message);
this.setState({
message: ''
});
}
render() {
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="message"
placeholder="아무거나 입력해 보세요"
value={this.state.message}
onChange={this.handleChange}
/>
<button onClick={this.handleClick}>확인</button>
</div>
);
}
}
export default EventPractice;
input
이 여러 개일 때는 메소드를 여러 개 만들면 될까? 그것보다 효율적인 방법이 있겠지... 바로 event 객체를 활용하는 것이다. input
태그에 name
속성을 줬기 때문에 그걸 이용해서 state
를 각각 다르게 설정하면 된다. 아래 코드로 예시를 들겠다.
import React, { Component } from ‘react‘;
class EventPractice extends Component {
state = {
username: '',
message: ''
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
handleClick = () => {
alert(this.state.username + ': ' + this.state.message);
this.setState({
username: ",
message: "
});
}
render() {
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="username"
placeholder="사용자명"
value={this.state.username}
onChange={this.handleChange}
/>
<input
type="text"
name="message"
placeholder="아무거나 입력해 보세요"
value={this.state.message}
onChange={this.handleChange}
/>
<button onClick={this.handleClick}>확인</button>
</div>
);
}
}
export default EventPractice;
코드를 잘 살펴 보면 아래 코드 부분에서 객체의 key
가 [ ]로 감싸져 있는 것을 볼 수 있다. 이는 이 안의 레퍼런스가 가리키는 실제 값을 key
값으로 사용한다는 뜻이다.
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
Enter
를 눌렀을 때 버튼을 클릭한 것과 같은 이벤트를 주기 위해 아래의 코드를 추가해 주고, input 태그에 onKeyPress={this.handleKeyPress}
속성을 준다.
handleKeyPress = (e) => {
if (e.key === 'Enter') {
this.handleClick();
}
}
지금까지 작성한 코드를 함수형 컴포넌트로 바꿔 보자. 그러려면 useState
를 써야겠지??
import React, { useState } from 'react';
const EventPractice = () => {
const [form, setForm] = useState({
username: '',
message: ''
});
const { username, messgae } = form;
const onChange = e => {
const nextForm = {
...form, // 기존의 form 내용을 이 자리에 복사한 뒤
[e.target.name]: e.target.value // 원하는 값을 덮어 씌우기
};
setForm(nextForm);
};
const onClick = () => {
alert(username + ': ' + message);
setForm({
username: '',
message: ''
});
};
const onKeyPress = e => {
if (e.key === 'Enter') {
onClick();
}
};
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="username"
placeholder="사용자명"
value={username}
onChange={onChange}
/>
<input
type="text"
name="message"
placeholder="아무거나 입력해 보세요"
value={message}
onChange={onChange}
onKeyPress={onKeyPress}
/>
<button onClick={onClick}>확인</button>
</div>
);
};
export default EventPractice;