사용자가 웹 브라우저에서 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;