React를 다루는 기술 05 - 이벤트 핸들링
사용자가 브라우저에서 DOM 요소들과 상호작용하는것을 이벤트라고 한다.
onclick, onmouseover, onkeypress등 HTML을 다룰 때 거의 필수적으로 사용하게 되는데 이러한 함수들은 React에서도 그대로 사용되나 다만 사용법 자체에 조금 차이가 있다.
const Say = () => {
const [message, setMessage] = useState('');
const onClickEnter = () => {setMessage('안녕하세요!')};
return (
<div>
<button onClick={onClickEnter}>입장</button>
</div>
)
}
-
이벤트 이름은 카멜케이스로 표기한다.
HTML에서 사용할 때에는 onclick와 같이 써도 상관없지만 jsx에서 사용할 때는 꼭 onClick와 같은 카멜케이스로 표기해야 에러가 나지 않는다. -
이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아니라, 함수 형태의 값을 전달한다.
HTML에서 이벤트를 실행할 때는 큰따옴표 안에 자바스크립트 코드를 넣어주었지만 jsx에서는 함수형태의 값을 넣어야한다.
이는 자바스크립트 코드로 넣을 경우 렌더링이 완료되기 전에 내부의 자바스크립트 코드가 실행되어 에러가 나는 것을 방지하기 위함이다. -
DOM 요소에만 이벤트를 설정할 수 있다.
div, input, button과 같은 DOM요소가 아닌 컴포넌트에서 이벤트를 설정하려고 하면 해당 함수가 prop으로 전달되어버린다.
물론 전달받은 prop을 통해 자식 컴포넌트에서 해당 함수를 실행할 수는 있지만 일반적으로는 자식 컴포넌트 내부에서 정의되어야하며 필요한 값이 있다면 해당 값을 prop으로 전달하면된다.
리액트에서 지원하는 이벤트의 종류는 이하와 같다.
- Clipboard
- Touch
- Composition
- UI
- Keyboard
- Wheel
- Focus
- Media
- Form
- Image
- Mouse
- Animation
- Selection
- Transition
이벤트 핸들링 예제
// EventPractice.js
import React from 'react';
const EventPractice = () => {
return (
<div>
<h1>이벤트 예제</h1>
<input
type="text"
name="message"
placeholder="아무거나 입력해보세요."
onChange={
(e) => {
console.log(e);
}
}
/>
</div>
)
}
export default EventPractice;
// App.js
import React from 'react';
import EventPractice from './EventPractice';
const App = () => {
return <EventPractice />
}
export default App;
위의 코드는 input에 값을 입력하여 값이 변경되면 onChange함수가 작동하여 콘솔에 입력값을 출력하는 코드이다.
여기서 onChange의 화살표 함수의 파라미터인 e는 SyntheticEvent로 웹 브라우저의 네이티브 이벤트를 감싸는 객체이다.
일반적인 HTML코드에서도 동일하게 사용된다.
여기서 주의할 점은 이 SyntheticEvent의 값은 사용이 종료되는 시점에서 null로 초기화된다는 점이다.
때문에 비동기식으로 사용하고자 할 때는 다른 변수에 담아서 전달하거나 e.persist() 함수를 사용해서 초기화되지 않도록 해야한다.
단, 이러한 방식은 성능에 조금 영향을 미친다고 하니 무거운 페이지를 렌더링 할 때는 지양하는 편이 좋다.
State에 input값 담기 예제
// EventPractice.js
import React, {useState} from 'react';
const EventPractice = () => {
const [message, setMessage] = useState('');
return (
<div>
<h1>이벤트 예제</h1>
<input
type="text"
name="message"
placeholder="아무거나 입력해보세요."
value={message}
onChange={
(e) => {
setMessage(e.target.value);
}
}
/>
{/* 버튼을 클릭하면 message값이 초기화된다. */}
<button onClick={
() => {
alert(message);
setMessage('');
}
}>확인</button>
</div>
)
}
export default EventPractice;
위의 코드에서 onChange, onClick함수 내의 코드들을 바깥으로 꺼내 임의의 함수로 담을 수 있습니다.
// EventPractice.js
import React, {useState} from 'react';
const EventPractice = () => {
const [message, setMessage] = useState('');
function handleChange(e) {
setMessage(e.target.value);
}
function handleClick() {
alert(message);
setMessage('');
}
return (
<div>
<h1>이벤트 예제</h1>
<input
type="text"
name="message"
placeholder="아무거나 입력해보세요."
value={message}
onChange={handleChange(e)}
/>
<button onClick={handleClick()}>확인</button>
</div>
)
}
export default EventPractice;
처음 말했듯 jsx의 이벤트함수에는 함수형 값을 전달해야하기 때문에 기존의 예제에서는 화살표 함수로 감싼 자바스크립트 코드를 사용했으나
이처럼 외부에서 함수로 정의하고 넣어주면 그럴 일이 없다.
성능적인 차이는 거의 없으므로 상황에 따라 쓰기 편하거나 가독성이 좋은 쪽을 고르면 된다.
만약 클래스형 컴포넌트에서 위와 같이 함수를 사용할 경우에는 바인딩을 해주어야한다.
이는 함수와 클래스의 관계를 나타내는 this가 렌더링되는 과정에서 관계성이 끊겨서 해당 함수가 어느 클래스에 속해있는지 찾을 수 없게되기 때문이다.
이 작업은 생성자 함수에서 진행하는 것이 기본이지만 화살표 함수를 통해 함수 선언시 바로 진행할 수도 있다.
input 여러개 다루기
이러한 이벤트를 다룰 때 만약 input이 여러개라면 어떨까.
각 state에 대항하는 함수를 여러개 만드는 방법도 있겠지만 불필요하게 함수를 늘리지 않고 event 객체를 통해 해당 DOM의 name값을 찾아서 진행하는 방법도 있다.
// EventPractice.js
import React, {useState} from 'react';
const EventPractice = () => {
const [form, setForm] = useState({
message: '',
title: ''
});
const {message, title} = form;
function handleChange(e) {
setForm({
...form,
[e.target.name]: e.target.value
});
}
function handleClick() {
setForm({
message: '',
title: ''
);
}
return (
<div>
<h1>이벤트 예제</h1>
<input
type="text"
name="message"
placeholder="아무거나 입력해보세요."
value={message}
onChange={handleChange(e)}
/>
<input
type="text"
name="title"
placeholder="아무거나 입력해보세요."
value={title}
onChange={handleChange(e)}
/>
<button onClick={handleClick()}>확인</button>
</div>
)
}
export default EventPractice;
위와 같이 e.target.name을 통해 해당 input의 name값을 가져올 수 있으며 name과 state 변수명을 동일하게 지정해줌으로써 1개의 함수로 2개의 input을 대응할 수 있다.
출처자료
https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=209354690 (리액트를 다루는 기술(개정판))