React의 이벤트 처리(이벤트 핸들링; Event handling) 방식은 DOM의 이벤트 처리 방식과 유사하다. 단, 몇 가지 문법 차이가 있다.
- React 에서 이벤트는 소문자 대신 카멜 케이스(camelCase) 를 사용한다.
- JSX를 사용하여 문자열이 아닌 함수로 이벤트 처리 함수(이벤트 핸들러; Event handler)를 전달한다.
- 이벤트 핸들러는 props로 전달할 수 있다.
예를 들어 HTML에서 이벤트 처리 방식이 아래와 같다면,
<button onclick="handleEvent()">Event</button>
React의 이벤트 처리 방식은 아래와 같다.
<button onClick={handleEvent}>Event</button>
자주 사용되는 이벤트 처리에 대해 알아보자.
onChange
<input> <textarea> <select> 와 같은 폼(Form) 엘리먼트는 사용자의 입력값을 제어하는 데 사용된다.
- React 에서는 이러한 변경될 수 있는 입력값을 일반적으로 컴포넌트의 state 로 관리하고 업데이트한다.
- onChange 이벤트가 발생하면 e.target.value 를 통해 이벤트 객체에 담겨있는 input 값을 읽어올 수 있다.
아래 코드에 대한 설명
- 컴포넌트 return 문 안의 input 태그에 value 와 onChange 를 넣어주었다.
- onChange 는 input 의 텍스트가 바뀔 때마다 발생하는 이벤트이다.
- 이벤트가 발생하면 handleChange 함수가 작동하며, 이벤트 객체에 담긴 input 값을 setState 를 통해 새로운 state 로 갱신한다.
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
}
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
<h1>{name}</h1>
</div>
)
};
onClick
onClick 이벤트는 말 그대로 사용자가 클릭이라는 행동을 하였을 때 발생하는 이벤트이다. 버튼이나 <a> tag 를 통한 링크 이동 등과 같이 주로 사용자의 행동에 따라 애플리케이션이 반응해야 할 때 자주 사용한다.
그럼 위의 onChange 예시에 버튼을 추가하여 버튼 클릭 시 input tag 에 입력한 이름이 alert을 통해 알림 창이 팝업 되도록 코드를 추가해 보겠다. 아래의 코드는 잘못된 예시이다.
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
}
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
<button onClick={alert(name)}>Button</button> // 🟣 틀린 예시이다.
<h1>{name}</h1>
</div>
);
};
문제
- 위와 같이 onClick 이벤트에 alert(name) 함수를 바로 호출하면 input 박스에 'ㄱ' 입력이 시작되고 컴포넌트가 렌더링 될 때 함수 자체가 아닌 함수 호출의 결과가 onClick 에 적용된다.
- 버튼을 클릭할 때가 아닌, 컴포넌트가 렌더링 될 때에 alert 이 실행되고 따라서 그 결과인 undefined (함수는 리턴 값이 없을 때 undefined 를 반환)가 onClick 에 적용되어 클릭했을 때 아무런 결과도 일어나지 않는다.
- 렌더링할 때마다 해당 함수가 호출되기 때문에 성능 이슈가 우려된다. [공식 문서]
[정리]
onClick={alert(name)} (다른 예시: onClick={handleIncrease()} 등)와 같이 진행하게 된다면, 리턴 값이 onClick으로 전달되어서 함수 자체가 전달되는 것이 아니라, 함수의 결괏값이 전달된다.
** 즉, 기존 자바스크립트의 방법과 다르다 (아래 예시는 버튼을 클릭 할때 '클릭'이라고 적힌 안내창이 뜬다.)
<button onclick="alert(textContent)">클릭</button>
해결방법
- 따라서 onClick 이벤트에 함수를 전달할 때는 함수를 호출하는 것이 아니라 아래와 같이 리턴문 안에서 함수를 정의하거나 리턴문 외부에서 함수를 정의 후 이벤트에 함수 자체를 전달해야 한다.
[안 되는 사례 하나 더 정리]
<button onClick= {() => plusNumber}> 버튼입니다 </button>
익명함수가 화살표 함수 형태로 배치되어 있다. 이에 따라, Plus 버튼을 클릭 했을 때 plusNumber 함수가 리턴될 뿐 호출되지는 않는다.
오키.. 알았어.. 알겠다구
{} 안에 함수를 정의(그 안의 함수는 호출)하거나 함수 자체를 전달해야 한다.
// 함수 정의하기
return (
<div>
...
<button onClick={() => alert(name)}>Button</button>
...
</div>
);
};
// 함수 자체를 전달하기
const handleClick = () => {
alert(name);
};
return (
<div>
...
<button onClick={handleClick}>Button</button>
...
</div>
);
};
그냥 쉽게 onClick HSX는 이벤트가 일어나면 onClick = {} 속 함수를 (), 즉 호출하기 시작한다고 생각하면 된다.
Action item 1 : <select>
<select> 태그는 Form 엘리먼트의 하나로 사용자의 입력값을 제어하는 데 주로 사용된다. select tag 는 사용자가 drop down 목록을 열어 그중 한 가지 옵션을 선택하면, 선택된 옵션이 state 변수에 갱신된다. 즉, React에서는 이러한 변경될 수 있는 입력값을 일반적으로 컴포넌트의 state로 관리하고 업데이트를 한다.
미리 알아야 하는 select 태그
: 하위 태그로 option이 있으며 이 option을 사용자가 선택할 때 해당 value 값이 저장된다.
<select>
<option value="americano">아메리카노</option>
<option value="caffe latte">카페라테</option>
<option value="cafe au lait" selected>카페오레</option>
<option value="espresso">에스프레소</option>
</select>
select 태그와 관련된 state 값 갱신하기
import React, { useState } from "react";
import "./styles.css";
function SelectExample() {
const [choice, setChoice] = useState("apple"); // 여기서 state 변수명은 choice
const fruits = ["apple", "orange", "pineapple", "strawberry", "grape"];
const options = fruits.map((fruit, idx) => {
return <option key={idx} value={fruit}>{fruit}</option>; // idx를 키 값으로 줌
});
console.log(choice);
// 🟣 (3) 이때 핸들러 함수의 역할은 선택된 과일로 state를 갱신시켜주는 일을 한다.
// 🟣 (4) 핸들러 함수는 onChange 이벤트의 event 객체를 인자로 받아 사용할 수 있다.
// 🟣 (5) 여기서 event.target.value가 바로 해당 옵션의 값이다.
// (이벤트 객체에는 발생한 이벤트에 대한 모든 정보가 담겨있고, 그중
// target 속성에는 이벤트가 발생한 엘리먼트에 대한 정보가 담겨있다)
const handleFruit = (event) => {
// 🟣 (6)setChoice(state 갱신함수)가 호출되어 해당 옵션의 값이 인자로 전달되면
// state의 변수명인 choice의 값이 바뀐다.
setChoice(event.target.value)
};
return (
<div className="App">
// 🟣 (1) select 태그의 옵션을 선택하면 onChange 이벤트가 발생한다.
// 🟣 (2) 그에 따라 해당 이벤트에 할당되어 있는 handleFruit 핸들러 함수가 호출된다.
// options의 첫 번째 요소는 <option value={apple}>{apple}</option>; 이런식임
<select onChange={handleFruit}>{options}</select>
// 🟣 (7)react는 페이지를 렌더링하고 <h3> 태그의 내용이 event.target.value의 값으로 바뀐다.
<h3>You choose "{choice}"</h3>
</div>
);
}
export default SelectExample;
Action item 2 : Pop up
Pop up 역시 Pop up 의 open 과 close 를 state 를 통해 관리할 수 있다.
import React, { useState } from "react";
import "./styles.css";
function App() {
const [showPopup, setShowPopup] = useState(false); // state 변수명 showPopup
const togglePopup = (event) => {
if(showPopup===false){ // 🟣 (2) 초기값이 false였기에 버튼 클릭에 따라
setShowPopup(true) // 🟣 (3) showPopup의 값이 true가 된다.
} else(setShowPopup(false)) // 🟣 (6) showPopup 값이 true이기에 else에서 false로 바뀐다.
};
return (
<div className="App">
<h1>Pop Up</h1>
<button className="open"
onClick = {togglePopup} >Open me</button> // 🟣 (1) 처음 버튼 클릭시 함수가 호출된다
{showPopup ? ( // 🟣 (4) showPopup 값이 true면 "popup" div 생성
<div className="popup">
<div className="popup_inner">
<h2>Success!</h2>
<button className="close" onClick={togglePopup}> // 🟣 (5) 닫기위한 버튼 클릭
Close me // 똑같은 함수가 호출된다.
</button>
</div>
</div>
) : null} // 🟣 (7) showPopup 값이 false면 null (아무 것도 없음)
</div>
);
}
export default App;
- 버튼 클릭에 따라 Pop up이 열고 닫히기 위해서는 버튼을 눌렀을 때 togglePopup 함수가 호출 되어야 한다.
- 따라서 onClick 이벤트 처리로 togglePopup 함수를 넣어줘야 한다.
- 또한 버튼 클릭에 따라 state 저장변수인 showPopup의 상태가 바뀌어야 한다. state 저장변수가 갱신되기 위해서는 state 갱신함수인 setShowPopup 을 호출해야 한다.
- showPopup의 초깃값이 false 이므로 true로 바꿔 주기 위해 setShowPopup 에 true 를 넣어 호출한다.
- 다시 Pop up 창을 닫기 위해서는 showPopup 을 false 로 바꿔주기 위해 setShowPopup 에 false 를 넣어 호출한다.
Controlled Component
간단한 글을 쓰면 전체 글이 업데이트가 되는 등 간단한 기능 위주로 트위터와 비슷하게 만들어보자고 가정해보자.
변하는 값? 변하지 않는 값?
변하지 않는 값
- 트윗을 받는 사람 (팔로워 등)
변할 수 있는 값, 상태 (state)
- 트윗을 보내는 사람 (누가 작성하는가에 따라 변경) -> username
- 트윗의 내용 -> tweet
React에서는 이렇게 상태에 해당하는 데이터를 state로 따로 관리하고 싶어 한다. 이렇게 React가 state를 통제할 수 있는 컴포넌트를 Controlled Component라고 한다. (Hooks로 Controlled Component 구현에 대해서 더 자세히 알고 싶으시면 공식 문서의 해당 링크를 참고)
React가 state를 통제하는 방법
- input에 값 입력 시, state도 그때그때 바뀌면(onChange) 된다.
- 그리고 이 변경된 state와 input의 value 또한 같게 작성해야 한다.
input과 textarea value의 변경에 따라, react의 state가 변경된다.
import "./styles.css";
import React, { useState } from "react";
export default function App() {
const [username, setUsername] = useState(""); // 🟡 state 변수명은 username
const [msg, setMsg] = useState(""); // 🟣 state 변수명은 msg
return (
<div className="App">
<div>{username}</div>
<input
type="text"
value={username} // 🟡 input의 value도 state 값으로 변경된다.
onChange={(event) => setUsername(event.target.value)}
placeholder="여기는 인풋입니다."
className="tweetForm__input--username">
// 🟡 입력이 감지되면 setUsername함수에 해당 인풋박스 속 내용이 인자로 전달되고 state 값도 변경된다.
</input>
<div>{msg}</div>
<textarea
placeholder="여기는 텍스트 영역입니다."
className="tweetForm__input--message" value={msg}
onChange={(event) => setMsg(event.target.value)} >
// 🟣 입력이 감지되면 setMsg함수에 해당 인풋박스 속 내용이 인자로 전달되고 state 값도 변경된다.
// 🟣 textarea의 value 속성도 state 값이 들어간다.
</textarea>
</div>
);
}
'FE > React' 카테고리의 다른 글
[React] State & Props로 간단한 트위터 기능 구현하기 (0) | 2023.03.27 |
---|---|
[React] React 데이터 흐름 (0) | 2023.03.24 |
[React] React에서 데이터를 다루는 Props & State (0) | 2023.03.24 |
[React] React로 Router 기능을 담은 SPA 구현해보기 + useNavigate (0) | 2023.03.23 |
[React] React Router로 간단한 메뉴 페이지 구현하기 (0) | 2023.03.23 |