게시글은 리액트 공부용이며 출처를 제시합니다.
출처: 소플의 처음 만난 React, 리액드를 다루는 기술, 모던 자바스크립트 deep dive
컴퓨터 프로그래밍에서 이벤트는 사건이다.
예를 들면 사용자가 버튼을 클릭하는 사건도 하나의 이벤트라고 볼 수 있다.
여기에서 클릭한 사건을 클릭 이벤트라고 부른다.
DOM의 이벤트
<button onclick="activate()">
Active
</button>
React의 이벤트
<button onClick={activate}>
Active
</button>
React에서는 카멜 케이스를 사용한다.
이벤트 처리 함수를 문자열이 아닌 함수 그대로를 전달한다.
DOM 요소에만 이벤트를 설정할 수 있다.
<MyComponent onClick={doSomething}/>
<div onClick={this.props.onClick}></div>
이벤트 핸들러
어떤 이벤트가 발생했을 때 해당 이벤트를 처리하는 함수가 있는데 이것을 이벤트 핸들러라고 한다. 또는 이벤트가 발생하는 것을 계속 듣고 있다는 의미로 이벤트 리스너라고 부르기도 한다.
function Toggle(props){
const [isToggleOn, setIsToggleOn] = useState(true);
//화살표 함수 사용
const handleClick = () => {
setIsToggle((isToggleOn) => !isToggleOn);
}
return (
<button onClick={handleClick}>
{isToggleOn? "켜짐":"꺼짐"}
</button>
);
}
Arguments는 주장, 논쟁, 말다툼이라는 뜻이 있다. 여기서는 주장이라는 뜻에 더 가깝다. 함수에 주장할 내용이라고 이해하면 된다.
함수에 전달할 데이터를 Arguments라고 하며 같은 의미로 파라미터라고도 한다. 한국말로는 매개변수라고 부른다.
이벤트 핸들러에게 매개변수를 전달해야 하는 경우는 많다.
예를 들어 특정 사용자 프로필을 클릭했을 때 해당 사용자의 아이디를 매개변수로 전달해서 정해진 작업을 처리해야 하는 경우가 있다.
function MyButton(props){
const handleDelete = (id, event) => {
console.log(id, event.target);
};
return (
<button onClick={(event)=> handleDelete(1, event)}>삭제하기</button>
)
}
<input
type="text"
name="message"
placeholder="입력하세요"
onChange={(e) => {
console.log(e);
}}
/>
콘솔에 기록되는 e
객체는 SyntheticEvent로 웹 브라우저의 네이티브 이벤트를 감싸는 객체이다.
Your event handlers will be passed instances of SyntheticEvent, a cross-browser wrapper around the browser’s native event. It has the same interface as the browser’s native event, including
stopPropagation()
andpreventDefault()
, except the events work identically across all browsers.
📍SyntheticEvent는 네이티브 이벤트와 달리 이벤트가 끝나고 나면 이벤트가 초기화되므로 정보를 참조할 수 없다.
따라서 onChange
를 주고 "안녕하세요"에서 한글자 씩 작성할때 마다 콘솔에 이벤트 객체는 나타나지만 각각 이벤트들의 value 값을 보면 전부 "안녕하세요"라고 쓰여 있다. "ㅇ","ㅏ","ㄴ" 이 아니라
만약 비동기적으로 이벤트 객체를 참조할 일이 있다면 e.persist()
함수를 호출한다.
만약 인풋값을 하나하나 출력하고 싶다면 e.target.value
로 확인하자
그럼 값이 바뀔 때마다 바뀌는 값을 콘솔에 기록하게 된다.
const EventPractice = () => {
const [message, setMessage] = useState("");
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="message"
placeholder="입력하세요"
value={message}
onChange={(e) => {
setMessage(e.target.value);
}}
/>
<h2>{message}</h2>
//h2태그에 input에 작성한 값이 실시간으로 렌더링되면서 나타난다. state에 바뀌는 값을 담아서
</div>
);
};
const EventPractice = () => {
const [message, setMessage] = useState("");
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="message"
placeholder="입력하세요"
value={message}
onChange={(e) => {
setMessage(e.target.value);
}}
/>
<button
onClick={() => {
//변수값을 문자열로 나타내야 알림창에 문자열 값이 출력된다.
//그렇지 않으면 "Object object"가 출력된다.
alert(`${message}`);
setMessage("");
}}
>
please click to reset
</button>
</div>
);
};
이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아니라 함수 형태의 값을 전달한다. 위에서는 이벤트 처리를 할 때 렌더링 하는 동시에 함수를 만들어서 전달했다.
이 방법 대신 함수를 미리 준비하여 전달하는 방법도 있다.
성능상으로는 차이가 거의 없지만 가독성은 훨씬 높다.
메서드 이름 정하는 쉬운 방법
규칙이 따로 있는 것은 아니지만 시작은 handle로 하는 것을 권장한다.
const EventPractice = () => {
const [message, setMessage] = useState("");
const handleChange = (e) => {
setMessage(e.target.value);
};
const handleClick = () => {
alert(`${message}`);
setMessage("");
};
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="message"
placeholder="입력하세요"
value={message}
onChange={handleChange}
/>
<h2>{message}</h2>
<button onClick={handleClick}>please click to reset</button>
</div>
);
};
지금까지 input 값은 state에 넣는 방법을 알아봤다. 하지만 input이 여러 개일 때는 어떻게 작업을 할까?
const EventPractice = () => {
const [message, setMessage] = useState("");
const [userName, setUserName] = useState("");
const handleMessageChange = (e) => {
setMessage(e.target.value);
};
const handleNameChange = (e) => {
setUserName(e.target.value);
};
const handleClick = () => {
alert(`${userName} : ${message}`);
setMessage("");
setUserName("");
};
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="username"
placeholder="사용자명"
value={userName}
onChange={handleNameChange}
/>
<input
type="text"
name="message"
placeholder="입력하세요"
value={message}
onChange={handleMessageChange}
/>
<h2>{`${userName} : ${message}`}</h2>
<button onClick={handleClick}>please click to reset</button>
</div>
);
};
export default EventPractice;
키를 눌렀을 때 발생하는 KeyPress 이벤트를 처리해보자.
comment
인풋에서 enter를 눌렀을 때 handleClick
메서드를 호출하도록 해보자
const EventPractice = () => {
const [message, setMessage] = useState("");
const [userName, setUserName] = useState("");
const handleMessageChange = (e) => {
setMessage(e.target.value);
};
const handleNameChange = (e) => {
setUserName(e.target.value);
};
const handleClick = () => {
alert(`${userName} : ${message}`);
setMessage("");
setUserName("");
};
const handleKeyPress = (e) => {
if (e.key === "Enter") {
handleClick();
}
};
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="username"
placeholder="사용자명"
value={userName}
onChange={handleNameChange}
/>
<input
type="text"
name="message"
placeholder="입력하세요"
value={message}
onChange={handleMessageChange}
//두번째 인풋창 작성하고 엔터를 누르면 handleClick 함수가 실행된다.
onKeyPress={handleKeyPress}
/>
<h2>{`${userName} : ${message}`}</h2>
<button onClick={handleClick}>please click to reset</button>
</div>
);
};
export default EventPractice;
이렇게 input창이 두 개밖에 없다면 이런 코드는 나쁘지 않지만 만약 인풋의 갯수가 1억개가 넘는다면 e.target.name
을 활용하여 useState를 문자열이 아닌 객체를 넣어보는 것이 효율적이다.
const EventPractice = () => {
const [form, setForm] = useState({
username: "",
message: "",
});
const { username, message } = form;
//구조분해할당
const onChange = (e) => {
const nextForm = { ...form, [e.target.name]: e.target.value };
//form은 객체이기 때문에 데이터를 수정할때 얕은 복사로 불변성을 지킨다.
//객체 안에서 key를 []로 감싸면 그 안에 넣은 레퍼런스가 가리키는 실제 값이 key값으로 사용된다.
setForm(nextForm);
};
const handleClick = () => {
alert(username + ":" + message);
setForm({
username: "",
message: "",
});
};
const handleKeyPress = (e) => {
if (e.key === "Enter") {
handleClick();
}
};
return (
<div>
<h1>이벤트 연습</h1>
<input
type="text"
name="username"
placeholder="사용자명"
value={username}
onChange={onChange}
/>
<input
type="text"
name="message"
placeholder="입력하세요"
value={message}
onChange={onChange}
onKeyPress={handleKeyPress}
/>
<h2>{`${username} : ${message}`}</h2>
<button onClick={handleClick}>please click to reset</button>
</div>
);
};
export default EventPractice;
여러 input 엘리먼트를 제어해야할 때, 각 엘리먼트에 name 어트리뷰트를 추가하고 event.target.name
값을 통해 핸들러가 어떤 작업을 할 지 선택할 수 있게 해줍니다.
주어진 input 태그의 name에 일치하는 state를 업데이트하기 위해 계산된 속성명을 사용한다.