사용자가 웹 브라우저에서 DOM 요소들과 상호 작용하는 것을 이벤트(event) 라고 합니다.
그렇다면 HTML에서 DOM 요소에 이벤트를 설정하는 방법을 한번 살펴봅시다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button onclick="alert('나였으면~')"> 성시경 </button>
</body>
</html>
button 태그 안에 이벤트 함수를 불러오는 방식으로 사용됩니다.
리액트 이벤트는 일반 HTML에서 이벤트를 작성하는 것과 비슷한데, 주의해야 할 몇 가지 사항이 있습니다.
input 요소를 렌더링 하는 코드를 작성해 봅시다.
<input type="text" name="message" placeholder="아무거나 입력 고고" onchange={(e)=>{ consol.log(e)}} />
위에서 사용되는 (e) 객체는 SyntheticEvent로 웹 브라우저의 네이티브 이벤트를 감싸는 객체입니다. 네이티브 이벤트와 인터페이스가 같으므로 순수 자바스크립트에서 HTML 이벤트를 다룰 때와 똑같이 사용하면 됩니다.
만약 비동기적으로 이벤트 객체를 참조할 일이 있다면 e.persist()함수를 호출해 주어야 합니다.
import { 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 });
}}
></input>
</div>
);
}
}
export default EventPractice;
input에 아무것나 입력해 보고 오류가 발생하지 않은 경우 제대로 입력할 수 있다면, state에 텍스트를 잘 담은 것입니다.
다음은 버튼을 눌렀을 시 comment 값을 공백으로 설정해 봅시다.
import { 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;
위 코드는 button 클릭 시 input 박스 안에 있는 텍스트를 alert로 출력하고, 안의 값을 setState로 초기화 시켜주는 기능입니다.
주의 사항에서 “이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아니라, 함수 형태의 값을 전달합니다” 라고 배웠습니다.
이를 함수를 미리 준비하여 전달하는 방법으로 성능상으로는 큰 차이 없지만, 가독성이 훨씬 높습니다.
onChange와 onClick에 전달한 함수를 따로 빼내서 컴포넌트 임의 메서드를 만들어 봅시다.
import { Component } from "react";
class EventPractice extends Component {
state = { message: "" };
constructor(props) {
super(props);
this.handlChange = this.handlChange.bind(this);
this.handlClick = this.handlClick.bind(this);
}
handlChange(e) {
this.setState({
message: e.target.value,
});
}
handlClick(e) {
alert(this.state.message);
this.setState({ message: "" });
}
render() {
return (
<div>
<h1> 이벤트 연습 </h1>
<input
type="text"
name="message"
placeholder="아무거나 입력해 보세요"
value={this.state.message}
onChange={this.handlChange}
/>
<button onClick={this.handlClick}>확인</button>
</div>
);
}
}
export default EventPractice;
bind() 함수는 this가 특정 HTML 요소의 이벤트로 등록되는 과정에서 메서드와 관계가 끊어져 버리기 때문에 임의 메서드가 이벤트로 등록 되어도 this가 컴포넌트 자신으로 제대로 가리키기 위해서 메서드를 this와 바인딩 하는 작업을 하도록 한것입니다.
이를 처리 하지 않을 경우 this가 undefined를 가리키게 됩니다.
이후 handleChange, handleClick 임의 메서드를 만들어 state 값을 넣어 줍니다.
메서드 바인딩은 생성자 메서드에서 하는 것이 정석입니다. 하지만 이 작업을 불편하다고 느낄 수 있습니다. 새 메서드를 만들 때 마다 constructor도 수정해야 하기 때문인데요,
이작업을 좀 더 간단하게 하는 방법이 있습니다. 바로 바벨의 transform-class-properties 문법을 이용하는 것입니다.
import { Component } from "react";
class EventPractice extends Component {
state = { message: "" };
handlChange = (e) => {
this.setState({
message: e.target.value,
});
};
handlClick = () => {
alert(this.state.message);
this.setState({ message: "" });
};
render() {
return (
<div>
<h1> 이벤트 연습 </h1>
<input
type="text"
name="message"
placeholder="아무거나 입력해 보세요"
value={this.state.message}
onChange={this.handlChange}
/>
<button onClick={this.handlClick}>확인</button>
</div>
);
}
}
export default EventPractice;
화살표 문법으로 훨씬 더 간결하게 만들 수 있습니다.
위에서 input 값을 state에 넣는 방법을 배웠습니다. 하지만 input 여러개 일 경우에는 어떻게 작업을 해야 할까요?
바로 event 객체를 활용하는 것 입니다.
e.tartget.name 값을 사용하면 됩니다.
onChange 이벤트 핸들러에서 e.target.name은 해당 인풋의 name을 가르킵니다. 지금은 message 겠죠? 이 값을 사용하여 state를 설정하면 쉽게 해결 할 수 있습니다.
import { Component } from "react";
class EventPractice extends Component {
state = { message: "", username: "" };
handlChange = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
};
handlClick = () => {
alert(this.state.username + ": " + this.state.message);
this.setState({ message: "", username: "" });
};
render() {
return (
<div>
<h1> 이벤트 연습 </h1>
<input
type="text"
name="username"
placeholder="이름을 입력하세요"
value={this.state.username}
onChange={this.handlChange}
/>
<input
type="text"
name="message"
placeholder="아무거나 입력해 보세요"
value={this.state.message}
onChange={this.handlChange}
/>
<button onClick={this.handlClick}>확인</button>
</div>
);
}
}
export default EventPractice;
state에 username 값을 넣어주고, handleChange 부분에서 [e.target.name]: 값을 변경 해주면서 input 에 설정 되어있는 name 값으로 값을 설정합니다.
handlChange = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
};
위에가 핵심 코드인데 객체 안에서 key를 [ ] 로 감싸면 그 안에 넣은 레퍼런스가 가리키는 실제 값이 key 값으로 사용됩니다.
이번에는 키를 눌렀을 때 발생하는 KeyPress 이벤트를 처리하는 방법을 알아보겠습니다. comment 인풋에서 enter를 눌렀을 때 handleClick 메서드를 호출하도록 작성 해봅시다.
import { Component } from "react";
class EventPractice extends Component {
state = { message: "", username: "" };
handlChange = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
};
handlClick = () => {
alert(this.state.username + ": " + this.state.message);
this.setState({ message: "", username: "" });
};
handleKeyPress = (e) => {
if (e.key === "Enter") {
this.handlClick();
}
};
render() {
return (
<div>
<h1> 이벤트 연습 </h1>
<input
type="text"
name="username"
placeholder="이름을 입력하세요"
value={this.state.username}
onChange={this.handlChange}
/>
<input
type="text"
name="message"
placeholder="아무거나 입력해 보세요"
value={this.state.message}
onChange={this.handlChange}
onKeyDown={this.handleKeyPress}
/>
<button onClick={this.handlClick}>확인</button>
</div>
);
}
}
export default EventPractice;
handleKeyPress 임의 메서드를 만들고 적용! onKeyDown 붙여주기