일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 스레드 제어와 생명 주기
- contatiner
- 자바 입출력 스트림
- 컨테이너
- Java IO
- 시작하세요! 도커 & 쿠버네티스
- 도커 엔진
- Collection
- 도커
- Docker
- 김영한
- 자바
- 시작하세요 도커 & 쿠버네티스
- Thread
- filewriter filereader
- container
- java
- 멀티 쓰레드
- 자료구조
- 알고리즘
- 쓰레드
- Kubernetes
- 리스트
- 쿠버네티스
- 스레드
- 동시성
- LIST
- 실전 자바 고급 1편
- 자바 io 보조스트림
- 인프런
- Today
- Total
쌩로그
리액트를 다루는 기술 - 04. 이벤트 핸들링 본문
목록
- 포스팅 개요
- 본론
2-1. 리액트의 이벤트 시스템
2-2. 예제로 이벤트 핸들링 익히기
2-3.함수형 컴포넌트로 구현해보기 - 요약
1. 포스팅 개요
해당 포스팅은 리액트를 다루는 기술의 04장 이벤트 핸들링
을 학습하며 정리한 포스팅이다.
2. 본론
사용자가 웹 브라우저에서 DOM 요소들과 상호 작용하는 것을 이벤트(event)
라고 한다.
예)
- 버튼에 마우스 커서를 올렸을 때는
onmouseover
- 마우스를 클릭했을 때는
onclick
- Form 요소의 값이 바뀔 때
onchange
2-1. 리액트의 이벤트 시스템
리액트의 이벤트 시스템은 웹 브라우저의 HTML 이벤트와 인터페이스가 동일하기 때문에 사용법이 꽤 비슷하다.
사용법은 HTML에서 이벤트를 작성하는 것과 비슷한데, 주의해야 할 몇 가지 사항이 있다.
이벤트 사용시 주의 사항
- 이벤트 이름은 카멜 표기법으로 작성한다.
- HTML의
onclick
을 리액트에서는onClick
으로 작성해야 한다. - HTML의
onkeyup
을 리액트에서는onKeyUp
으로 작성해야 한다.
- HTML의
- 이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아니라, 함수 형태의 값을 전달한다.
- 리액트에서는 함수 형태의 객체를 전달한다.
- 화살표 함수 분법으로 함수를 만들어 전달해도 되고, 렌더링 부분 외부에 미리 만들어서 전달할 수 있다.
- DOM 요소에만 이벤트를 설정할 수 있다.
- 즉 div, button, input, form, span 등의 DOM 요소에는 이벤트를 설정할 수 있지만, 직접 만든 컴포넌트에는 이벤트를 자체적으로 설정할 수 없다.
- 컴포넌트에 자체적으로 이벤트를 설정할 수는 없지만, 전달받은 props를 컴포넌트 내부의 DOM 이벤트로 설정할 수는 있다.
이벤트 종류
리액트에서 지원하는 이벤트 종류는 다음과 같다.
- Clipboard
- Composition
- Keyboard
- Focus
- Form
- Mouse
- Selection
- Touch
- UI
- Wheel
- Media
- Image
- Animation
- Transition
2-2. 예제로 이벤트 핸들링 익히기
컴포넌트 생성 및 불러오기
컴포넌트 생성
예제애 쓸 새 컴포넌트를 만든다.
import React, { Component } from "react";
class EventPractice extends Component {
render() {
return (
<div>
<h1>이벤트 연습</h1>
</div> );
}
}

다음과 같이 나옴을 확인할 수 있다.
onChange 이벤트 설정을 해보자.
방금 작성했던 EventPractice 컴포넌트에 input 요소를 렌더링하는 코드와 해당 요소에 onChange 이벤트를 설정하는 코드를 작성한다.
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;

다음과 같이 확인할 수 있다.
크롬 개발자 도구를 열고 input에 아무것이나 입력해보자.

위와 같은 Event 객체가 나온다.
콘솔에 기록되는 e 객체는 SyntheticEvent
로 웹 브라우저의 네이티브 이벤트를 감싸는 객체이다.
네이티브 이벤트와 인터페이스가 같으므로 순수 자바스크립트에서 HTML 이벤트를 다룰 떄와 똑같이 사용하면 된다.
SyntheticEvent
및 네이티브 이벤트와 달리 이벤트가 끝나고 나면 이벤트가 초기화되므로 정보를 참조할 수 없다.
예를 들어 0.5초 뒤에 e 객체를 참조하면 e 객체 내부의 모든 값이 비워지게 된다.
만약 비동기적으로 이벤트 객체를 참조할 일이 있다면 e.persist()
함수를 호출해주어야 한다.
onChange
이벤트가 발생할 때, 앞으로 변할 인풋 값인 e.target.value
를 콘솔에 기록해보자.
다음과 같이 코드를 수정한다.
...
onChange={
(e) => {
console.log(e.target.value);
}
}
...

'테스트'를 입력했는데, 값이 바뀌는 족족 콘솔에 출력되고 있다.

state에 input 값 담기
이제 state에 input 값을 담아보자.
생성자 메서드인 constructor
에서 state 초깃값을 설정하고, 이벤트 핸들링 함수 내부에서 this.setState
메서드를 호출하여 state를 업데이트 해보자.
그리고 input의 value값을 state에 있는 값으로 설정하자.
import React, { Component } from "react";
class EventPracticeInputValueAtState 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
})
}
}
/>
</div> );
}
}
export default EventPracticeInputValueAtState;
(컴포넌트 명은 예제마다 다르게 하려고 임의로 설정했다.)
input에 아무거나 입력했는데, 오류가 발생하지 않으면 state에 텍스트틀 잘 담은 것이다.
버튼을 누를 때 comment 값을 공백으로 설정
입력 값이 state에 잘 들어갔는지, 인풋에서 그 값을 제대로 반영하는지 검증해보자.
input 요소 코드 아래쪽에 button을 하나 만들고, 클릭 이벤트가 발생하면 현재 comment 값을 메시지 박스로 띄운 후 comment 값을 공백으로 설정한다.
import React, { Component } from "react";
class EventPracticeCommentBlank 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 EventPracticeCommentBlank;

여기서 확인을 누르면 아래와 같이 공백이 된다.

이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아니라, 함수 형태의 값을 전달한다라고 했었다. 그래서 이벤트 처리시 렌더링을 하는 동시에 함수를 만들어서 전달했다.
이 방법 대신 함수를 미리 준비하여 전달하는 방법도 있다.
성능상으로는 차이가 거의 없지만, 가독성은 훨씬 높다.(상황에 따라 렌더링 메서드 내부에서 함수를 만드는 것이 더 편할 때도 있다.)
onChange와 onClick에 전달한 함수를 따로 빼내서 컴포넌트 임의 메서드를 만들어보자.
기본 방식
import React, { Component } from "react";
class EventPracticeBasic extends Component {
state = {
message: ''
}
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
}
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 EventPracticeBasic;
기능은 이전과 동일하다.
Property Initializer Syntax를 사용한 메서드 작성
메서드 바인딩은 생성자 메서드에서 하는 것이 정석이다.
하지만 이 작업이 불편하다고 느낄 수 있다.
새 메서드를 만들 때마다 constructor
도 수정해야하기 때문이다.
해당 작업을 더 간단히 할 수 있는데, 바벨의 transform-class-properties
문법을 사용하여 화살표 함수 형태로 메서드를 정의하는 것이다.
import React, { Component } from "react";
class EventPracticeArrow 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 EventPracticeArrow;
contructor
를 없애면서 더 간결해졌다.
input 여러 개 다루기
input이 여러 개일 때는 메서드를 여러 개 만드는 것도 하나의 해법이지만, 더 쉽게 처리할 수 있다.
event 객체를 활용하는 것이다.e.target.name
을 사용하면 된다.
onChange
이벤트 핸들러에서 e.target.name
은 해당 인풋의 name(속성)을 가리킨다.
(지금은 message이다.)
이 값을 사용하여 state를 설정하면 쉽게 해결할 수 있다.
다음 코드는 render 함수에서 name값이 username인 input을 렌더링해 주었고,
state 쪽에도 username이라는 값을 추가해주었다.
그리고 handleChange도 조금 변경해주었다.
import React, { Component } from "react";
class EventPracticeMultiInput extends Component {
state = {
username: '',
message: ''
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
handleClick = () => {
alert(this.stte.username + ': ' + this.state.message);
this.setState({
username: '',
message: ''
});
}
render() {
return (
<div>
<h1>이벤트 연습</h1>
<input type="text"
name="username"
placeholder="사용자명"
value={this.state.message}
onChange={this.handleChange}
/>
<input type="text"
name="message"
placeholder="아무거나 입력해 보세요"
value={this.state.message}
onChange={this.handleChange}
/>
<button onClick={this.handleClick}>확인</button>
</div> );
}
}
export default EventPracticeMultiInput;

위와 같이 동작한다.
핵심 코드는 다음과 같다.
...
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
...
객체 안에서 key를 [ ]
로 감싸면 그 안에 넣은 레퍼런스가 가리키는 실제 값이 key 값으로 사용된다.
다음과 같은 객체를 만들면
const name = 'variantKey';
cont object = {
[name] : 'value'
};
결과는 다음과 같다.
{
'variantKey' : 'value'
}
onKeyPress 이벤트 핸들링
이번에는 키를 눌렀을 때 발생하는 KeyPress 이벤트를 처리하는 방법을 알아보자.
comment 인풋에서 Enter
를 눌렀을 떄 handleClick
메서드를 호출하도록 코드를 작성한다.
import React, { Component } from "react";
class EventPracticeOnKeyPress 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: ''
});
}
handleKeyDown = (e) => {
if(e.key === 'Enter') {
this.handleClick();
}
}
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}
onKeyDown={this.handleKeyDown}
/>
<button onClick={this.handleClick}>확인</button>
</div> );
}
}
export default EventPracticeOnKeyPress;
참고로 예제에 있는 onKeyPress
가 현재 Deprecated 되었으므로 onKeyDown
을 주었다.onKeyUp
도 있지만, onKeyDown
이 현재는 더 적합할 거 같다고 생각했다.
onKeyUp과 onKeyDonw의 차이는 다음 블로그에 잘 나와있다.
https://velog.io/@diso592/onKeyPress-is-deprecated
Enter
를 누르면 handleClick
메서드가 실행된다.
2-3.함수형 컴포넌트로 구현해보기
방금까지 했던 작업을 함수형 컴포넌트로도 똑같이 구현할 수 있다.
import React, {Component, useState} from "react";
const EventHandlingByFunction = () => {
const [username, setUsername] = useState('');
const [message, setMessage] = useState('');
const onChangeUsername = e => setUsername(e.target.value);
const onChangeMessage = e => setMessage(e.target.value);
const onClick = () => {
alert(username + ": " + message);
setUsername('');
setMessage('');
};
const onKeyDown = e => {
if (e.key === 'Enter') {
onClick();
}
}
return (
<div>
<h1>이벤트 연습</h1>
<input type="text"
name="username"
placeholder="사용자명"
value={username}
onChange={onChangeUsername}
/>
<input type="text"
name="message"
placeholder="아무거나 입력해 보세요"
value={message}
onChange={onChangeMessage}
onKeyDown={onKeyDown}
/>
<button onClick={onClick}>확인</button>
</div> );
}
export default EventHandlingByFunction;
위 코드에서는 e.target.name
을 활용하지 않고, onChange
관련 함수 두 개를 따로 만들어줬다.
인풋이 두 개 밖에 없다면 이런 코드도 나쁘지는 않다. 하지만 인풋의 개수가 많아질 것 같으면 e.target.name
을 활용하는 것이 더 좋을 수도 있다.
이번에는 useState
를 통해 사용하는 상태에 문자열이 아닌 객체를 넣어보자.
import React, {Component, useState} from "react";
const EventHandlingByObject = () => {
const [form, setForm] = useState({
username: '',
message: ''
});
const { username, message} = 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 onKeyDown = 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}
onKeyDown={onKeyDown}
/>
<button onClick={onClick}>확인</button>
</div> );
}
export default EventHandlingByObject;
e.target.naem
값을 활용하려면, useState를 쓸 때 인풋 값들이 들어 있는 form 객체를 사용해주면 된다.
3. 요약
리액트에서 이벤트를 다루는 것은 순수 자바스크립트 또는 JQuery를 사용한 웹 애플리케이션에서 이벤트를 다루는 것과 비슷하다.
리액트의 장점 중 하나는 자바스크립트에 익숙하다면 쉽게 활용할 수 있다는 것이다.
따라서 기존 HTML DOM Event를 알고 있다면 리액트의 컴포넌트 이벤트도 쉽게 다룰 수 있다.
함수형 컴포넌트에서 여러 개의 인풋 상태를 관리하기 위해 useState
에서 form 객체를 사용해보았다.
8장에서 배우는 userReducer와 커스텀 Hooks를 사용하면 이 작업을 훤씬 더 편하게 할 수 있다.
'Front > React' 카테고리의 다른 글
리액트를 다루는 기술 - 06. 컴포넌트 반복 (0) | 2024.04.10 |
---|---|
리액트를 다루는 기술 - 05. ref - DOM에 이름 달기 (0) | 2024.04.10 |
리액트를 다루는 기술 - 03. 컴포넌트 (0) | 2024.04.02 |
리액트를 다루는 기술 - 02. JSX (0) | 2024.03.26 |
리액트를 다루는 기술 - 01. 리액트 시작 (0) | 2024.03.26 |