안녕하세요! delay100입니다. 이번 포스팅에서는 이벤트 핸들링에 대해 공부해봅시다.
대부분의 설명은 주석으로 달아놓았으니 코드에 대한 설명은 주석을 확인해주세요!
책 리액트를 다루는 기술, 개정판의 4장 내용을 다루고 있습니다.
이번 포스팅의 Github 링크
https://github.com/delay-100/study-react/tree/main/ch4
1. event(이벤트)?
event(이벤트)란?
사용자가 웹 브라우저에서 DOM 요소들과 상호 작용하는 것
- html에서 이벤트 사용 예시 - 4.0/test.html
<!-- HTML에서 이벤트 실행하기 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<button onclick="alert('executed')">
Click Me
</button>
</body>
</html>
2. 리액트의 이벤트(클래스형 컴포넌트)
리액트의 이벤트 시스템에 대해 알아봅시다. 리액트의 이벤트 시스템은 4.0/test.html의 예시와 같이 인터페이스가 동일하기 때문에 사용법이 비슷합니다.
리액트의 이벤트 사용 시 주의 사항
1. 이벤트 이름은 카멜 표기법으로 작성. ex) onClick, onKeyUp
2. 함수 형태의 값을 전달. ex) html은 큰따옴표 안에 실행할 코드를 넣음
3. DOM 요소에만 이벤트 설정 가능. ex) div, button, input, form, span 등(자신이 만든 컴포넌트에는 설정 불가)
2-1. 함수 이벤트
단순하게 onClick과 onChange를 이용해 이벤트를 만들어봅시다. 이벤트를 처리할 때 렌더링 하는 동시에 함수를 만들어 전달하는 방법입니다.
- 클래스형 컴포넌트 & 함수 이벤트 생성 - 4.1/hello-react/src/EventPractice.js
// 기본 코드
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) => {
// 이벤트 렌더링 시 함수를 만들어 보내줌
// console.log(e);
console.log(e.target.value);
this.setState({
message: e.target.value,
});
}}
/>
<button
onClick={() => {
// 이벤트 렌더링 시 함수를 만들어 보내줌
alert(this.state.message); // 현재 comment 값을 메시지 박스로 띄움
this.setState({
// comment 값을 공백으로 설정
message: "",
});
}}
>
확인
</button>
</div>
);
}
}
export default EventPractice;
- 클래스형 컴포넌트 & 함수 이벤트 생성 - 4.1/hello-react/src/App.js
import EventPractice from "./EventPractice";
const App = () => {
return <EventPractice />;
};
export default App;
2-2. (함수) 메소드 이벤트
2-1의 코드와 같은 동작을 하는 이벤트를 만들어봅시다. 이번에는 메소드를 선언해 코드의 가독성을 더 높혀보겠습니다.
+state를 이용한 코드가 나오는데, 이전 포스팅에서 다뤘습니다. (여기 클릭)
- 클래스형 컴포넌트 & 함수 이벤트 메소드 생성 - 4.1/hello-react/src/EventPracticeMethod.js
// 기본 코드 -> 메서드로 변환한 코드
import { Component } from "react";
class EventPracticeMethod extends Component {
state = {
message: "",
};
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleChange(e) {
console.log(e.target.value);
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 EventPracticeMethod;
- 클래스형 컴포넌트 & 함수 이벤트 메소드 생성 - 4.1/hello-react/src/App.js
import EventPracticeMethod from "./EventPracticeMethod";
const App = () => {
return <EventPracticeMethod />;
};
export default App;
실행 결과는 2-1과 같습니다.
2-3. Property Initializer Syntax 이용 이벤트 메서드
2-2 처럼 메서드를 만드는 방법도 있지만, 위의 방법은 새 메서드를 만들 때마다 constructor도 수정해야하기 때문에 불편합니다. 이 작업을 더 간단하게 만들어봅시다.
바벨의 transform-class-properties 문법을 사용하여 화살표 함수 형태로 메서드를 정의하면 됩니다.
- 화살표 함수 형태로 이벤트 생성 - 4.1/hello-react/src/EventPracticePIS.js
// Property Initializer Syntax를 사용해 메서드 작성
import { Component } from "react";
class EventPracticePIS extends Component {
state = {
message: "",
};
handleChange = (e) => {
// 화살표 함수 형태로 메서드를 정의함
console.log(e.target.value);
this.setState({
message: e.target.value,
});
};
handleClick = () => {
alert(this.state.message);
this.setState({
message: "",
});
};
render() {
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="message"
paceholder="아무거나 입력해 보세요"
value={this.state.message}
onChange={this.handleChange}
/>
<button onClick={this.handleClick}>확인</button>
</div>
);
}
}
export default EventPracticePIS;
- 화살표 함수 형태로 이벤트 생성 - 4.1/hello-react/src/App.js
import EventPracticePIS from "./EventPracticePIS";
const App = () => {
return <EventPracticePIS />;
};
export default App;
실행 결과는 2-1과 같습니다.
2-4. 여러 개의 input 이벤트 처리
지금까지는 1개의 input만 다뤄보았습니다. 여러 개의 input을 처리하기 위해서, event 객체를 활용합니다.
e.target.name을 사용하면 됩니다. e.target.name은 해당 input의 name을 가리킵니다.
- 여러 개의 input 이벤트 처리 - 4.1/hello-react/src/EventPractice2Input.js
// 여러 개의 input 처리하기
import { Component } from "react";
class EventPractice2Input extends Component {
state = {
username: "",
message: "",
};
handleChange = (e) => {
// 화살표 함수 형태로 메서드를 정의함
console.log(e.target.value);
this.setState({
[e.target.name]: e.target.value, // 객체 안에서 key를 []로 감싸면 그 안에 넣은 레퍼런스가 가리키는 실제 값이 key 값으로 사용됨
// 즉, e.target.name으로 입력되는 값이 key(username, message)로 이용됨
});
};
handleClick = () => {
alert(this.state.username + ": " + this.state.message);
this.setState({
username: "",
message: "",
});
};
// Enter를 눌렀을 때 handleClick 메서드를 호출하도록 하는 코드 - onKeyPress 이벤트 핸들링
handleKeyPress = (e) => {
if (e.key === "Enter") {
this.handleClick();
}
};
render() {
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="username" // name이 username인 input을 render함
paceholder="사용자명"
value={this.state.username}
onChange={this.handleChange}
/>
<input
type="text"
name="message" // name이 messasge인 input을 render함
paceholder="아무거나 입력해 보세요"
value={this.state.message}
onChange={this.handleChange}
onKeyPress={this.handleKeyPress} // 이 input(2번째 input)에서 Enter 클릭 시 확인 버튼이 클릭됨
/>
<button onClick={this.handleClick}>확인</button>
</div>
);
}
}
export default EventPractice2Input;
- 여러 개의 input 이벤트 처리 - 4.1/hello-react/src/App.js
import EventPracticePIS from "./EventPracticePIS";
const App = () => {
return <EventPracticePIS />;
};
export default App;
3. 리액트의 이벤트(함수 컴포넌트)
3-1. 여러 개의 input 이벤트 처리
이번에는 2-4의 코드와 같은 동작을 하는 함수 컴포넌트를 만들어봅시다.
코드를 보면, useState가 많이 나오는데, useState에 대한 설명은 이 곳에 있습니다.(여기 클릭)
- 여러 개의 input 이벤트 처리 - 4.1/hello-react/src/EventPractice2InputFun.js
// 여러 개의 input 처리하기 - 함수 컴포넌트
import { useState } from "react";
const EventPractice2InputFun = () => {
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 onKeyPress = (e) => {
if (e.key === "Enter") {
onClick();
}
};
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="username"
paceholder="사용자명"
value={username}
onChange={onChangeUsername}
/>
<input
type="text"
name="message"
paceholder="아무거나 입력해 보세요"
value={message}
onChange={onChangeMessage}
onKeyPress={onKeyPress} // 이 input(2번째 input)에서 Enter 클릭 시 확인 버튼이 클릭됨
/>
<button onClick={onClick}>확인</button>
</div>
);
};
export default EventPractice2InputFun;
- 여러 개의 input 이벤트 처리 - 4.1/hello-react/src/App.js
import EventPractice2InputFun from "./EventPractice2InputFun";
const App = () => {
return <EventPractice2InputFun />;
};
export default App;
위의 4.1/hello-react/src/EventPractice2InputFun.js 코드는 input이 2개 정도 있는 경우에 사용할 수 있습니다. input 개수가 더 많아진다면 e.target.name을 이용하는게 더 좋을 수도 있습니다.
3-2. useState가 객체인 경우 input 처리
3-1은 여러 변수(username, message)를 다뤘지만, 이번에는 useState를 통해 사용하는 상태에 문자열이 아닌 객체를 넣어봅시다.
코드에 ...form이 있는데, form을 복사하는 것입니다. (이 블로그에 spread 연산자인 ...에 대해 설명이 잘 되어있습니다.)
- 여러 개의 input 이벤트 처리 - 4.1/hello-react/src/EventPractice2InputFun2.js
// 여러 개의 input 처리하기 - 함수 컴포넌트
import { useState } from "react";
const EventPractice2InputFun = () => {
const [form, setForm] = useState({
// 함수 호출 시 배열이 반환되는데, 배열의 첫 번째 원소: 현재 상태, 두 번째 원소: 상태를 바꾸어 주는 함수(세터(setter) 함수라고 함)
// useState가 객체 형태임
// useState함수 인자에 상태의 초기값을 넣어줌
username: "",
message: "",
});
const { username, message } = form;
const onChange = (e) => {
const nextForm = {
...form, // 기존의 form 내용을 이 자리에 복사한 뒤 - 이전거 가져오는 이유: 리액트에서 상태 불변성을 유지해야하기 위해서
// form은 username과 message의 원래 있던 값임
[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"
paceholder="사용자명"
value={username}
onChange={onChange}
/>
<input
type="text"
name="message"
paceholder="아무거나 입력해 보세요"
value={message}
onChange={onChange}
onKeyPress={onKeyPress} // 이 input(2번째 input)에서 Enter 클릭 시 확인 버튼이 클릭됨
/>
<button onClick={this.handleClick}>확인</button>
</div>
);
};
export default EventPractice2InputFun;
- useState가 객체인 경우 input 처리 - 4.1/hello-react/src/App.js
import EventPractice2InputFun2 from "./EventPractice2InputFun";
const App = () => {
return <EventPractice2InputFun2 />;
};
export default App;
실행 결과는 3-1과 같습니다.
마지막 부분에 ...form 부분이 잘 이해가 안되서 고생을 좀 했습니다..
사실 아직 정확히는 이해가 안되지만, react는 상태 불변성 유지..?가 중요하다고해서 일단은 그러려니 하고 넘어가려고 합니다.. 계속 반복해서 보다보면 느끼는 게 있을 것 같아 우선은 이렇게 써야한다..!! 느낌으로!! ㅎㅎ
읽어주셔서 감사합니다. 잘못된 정보는 댓글로 알려주세요!
'Study > React' 카테고리의 다른 글
6. map (0) | 2022.07.13 |
---|---|
5. ref (0) | 2022.07.12 |
3. Component(컴포넌트) (0) | 2022.07.10 |
2. JSX (0) | 2022.07.05 |
1. React 시작하기(yarn 설치 및 실행) (0) | 2022.07.04 |