React) 이벤트 핸들링

39018 단어 ReactReact

4. 이벤트 핸들링

사용자가 웹 브라우저에서 DOM 요소들과 상호 작용하는 것을 이벤트라고한다.
ex)타겟에 마우스커서를 올렸을 때는 onmouseover 이벤트를 실행, 클릭했을 때는 onclick를 실행하는것과 같다.

👀React에서의 이벤트와 JS이벤트의 차이?
**React 엘리먼트에서 이벤트를 처리하는 방식은 DOM 엘리먼트에서 이벤트를 처리하는 방식과 매우 유사하지만,
몇 가지 문법 차이는 다음과 같다.

ex:
🔶HTML
<button onclick="activateLasers()">
  Activate Lasers
</button>

🔷React
<button onClick={activateLasers}>
  Activate Lasers
</button>

자세한 내용은 리액트 공식홈페이지 에서 확인 가능하며🧐. 아래 내용에 계속해서 기록해보겠다!


4-1. 리액트의 이벤트 시스템

리액트의 이벤트 시스템은 웹 브라우저의 HTML 이벤트와 인터페이스가 동일하기 때문에 사용법이 꽤 비슷하다. 아래 코드는 3장에서 기록한 버튼코드이다.

import React, { useState } from 'react';

const Say = () => {
	const [message, setMessage] = useState('');
    const onClickEnter = () => setMessage('안녕하세요');
    const onClickLeave = () => setMessage('안녕히 가세요');
    
    return (
    	<div>
        	<button onClick={onClickEnter}>입장</button>
            <button onClick={onClickLeave}>퇴장</button>
            <h1>{message}</h1>
        </div>
    )
};

export default Say;

1.이벤트를 사용할 때 주의사항

  • 이벤트 이름은 카멜 표기법으로 작성한다.
  • 이벤트를 실행할 자바스크립트 코드를 전달하는 것이 아니라, 함수 형태의 값을 전달한다.
  • DOM 요소에만 이벤트를 설정할 수 있다. 즉 div, button, input, form, span등의 DOM 요소에는 이벤트를 설정할 수 있지만, 우리가 직접 만든 컴포넌트에는 이벤트를 차제적으로 설정할 수 없다.

2.이벤트 종류

  • keyboard
  • Focus
  • Form
  • Mouse
  • Touch...등등
    이걸 전부 다루진 않겠지만, 그밖의 이벤트는 나머지는 위에서 언급한 공식홈페이지를 참조해보면 되겠다.

4-2.이벤트 핸들링 익혀보기

1. 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;

위 코드중 콘솔에 기록될 'e' 객체는 SyntheticEvent로 웹 브라우저의 네이티브 이벤트를 감싸는 객체이다. 네이티브 이벤트와 인터페이스가 같으므로 순수 JS에서 HTML 이벤트를 다룰 때와 똑같이 사용하면 된다. 그리고 SyntheticEvent는 네이티브 이벤트와 달리 이벤트가 끝나고나면 이벤트가 초기화 되므로 정보를 참조할 수 없다. 만약 비동기적 이벤트 객체를 참조할 일이 있다면 e.persist() 함수를 호출해 주어야 한다. 그 이유는 리액트에서의 'e'파라미터는 브라우저에 사용되고 있는 이벤트타겟 객체와는 다르기 때문이다. 해당 'e'객체는 React에서 작성한 SyntheticEvent로 웹 브라우저에 있는 Event를 이용한 새로운 객체이기 때문이다.

👀왜 이벤트가 초기화 되는 것일까?
**리액트에서 사용되고 있는 SyntheticEvent는 객체 풀링 방식을 사용한다.(Object Pooling)
매 이벤트마다 해당 객체 사용되는것에 대해서 성능상의 이유로 리액트 에서는 객체 풀링 방식을 사용함으로써 
객체 생성 시간을 줄이고 GC(가비지콜렉터)에 대한 노출도 줄이며 메모리관리에 소비되는 시간을 줄이는 방식을 
사용하고 있기 때문이다. 그렇기 때문에 객체가 호출되고 난 후에 이벤트 속성이 초기화된다. 

2. state에 input 값 담고 버튼눌러 공백으로 설정하기

constructor에서 state 초깃값을 설정하고, 이벤트 핸들링 함수 내부에서 this.setState 메서드를 호출하여 state를 업데이트 해볼것이다.

import React, { 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) => {
                          this.setState({
                          	message: e.target.value
                          })
                      }
                  }
              />
              <button onClick={
              	() => {
                	alert(this.state.message);
                    this.setState({
                    	message: ''
                    });
                }
              }>확인</button>
          	</div>	
        )
    }
}

export default EventPractice;

3. 임의 메서드 만들기

함수를 미리 준비하여 전달하는 방법이 있다. 성능상의 차이는 없지만 가독성이 훨씬 높다는 장점이 있다. (하지만 상황에 따라 랜더링 메서드 내부에서 함수를 만드는것이 더 편할 떄도 있다.)

1.기본방식

import React, { Component } from 'react';

class EventPractice 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 EventPractice;
👀bind를 왜 썼을까?
**함수가 호출될 때 this는 호출부에 따라 결정되므로, 클래스긔 임의 에서드가 특정 HTML요소의 이벤트로 
등록되는 과정에서 메서드와 this의 관계가 끊어져버리기 때문에 this가 컴포넌트 자신을 제대로 가리키기 
위해서는 메서드를 this와 바인딩 하는 작업이 필요하다. 그렇지않으면 this는 undefind를 가리키게 된다.

2.Property Initializer Syntax를 사용한 메서드 작성

위와같이 생성자 메서드에서 메서드바인딩을 하는것이 정석이지만 새 메서드를 만들 때 마다 constructor도 수정해야 하기 때문에 불편할 수 있다. 그럴때에는 바벨의 transform-class-properties 문법을 사용해 화살표 함수 형태로 메서드를 정의 할 수 있다. 그러면 아래와 같은 깔끔한 코드로 정리할 수 있다.

import React, { Component } from 'react';

class EventPractice 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 EventPractice;

3. input 여러 개 다루기

input이 여러개 일 때 메서드를 여러 개 만들지 않고 쉽게 처리하는 방법이 있다. 바로 event객체를 활용하는 것 이다. onChange 이벤트 핸들러에서 e.target.name은 해당 인풋의 name를 가리킨다.

import React, { Component } from 'react';

class EventPractice 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: ''
        });
    }

	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}
              />
              <button onClick={this.handleClick}>확인</button>
          	</div>	
        )
    }
}

export default EventPractice;

객체 안에서 key를 [ ]로 감싸면 그 안에 레퍼런스가 가리키는 실제 값이 key 값으로 사용된다.


4-3. 함수컴포넌트로 구현하기

위 작업을 함수컴포넌트로 바꾸면 아래와 같아진다.

import React, { useState } from 'react';

const EventPractice = () => {
	const [username, setUsername] = useState('');
    const [message, setMessage] = useState('');
    const onChangeUsername = e => setUsername(e.target.value);
    const onChangeMessge = e => setMessage(e.target.value);
    const onClick = () => {
    	alret(username + ':' + message);
        setUsername('');
        setMessage('');
    };
	
    return (
    	<div>
        	<h1>이벤트 연습</h1>
            <input
            	type="text"
                name="username"
                placeholder="사용자명"
                value="{username}"
                onChange={onChangeUsername}
            />
            <input
            	type="text"
                name="message"
                placeholder="아무거나 입력해 보세요"
                value="{message}"
                onChange={onChangeMessge}
              />
            <button onClick={onClick}>확인</button>
		</div>	
	)
}

export default EventPractice;

useState 를 사용해 코드가 좀더 간결해진것을 알 수 있었다. 그리고 리액트의 장점 중 하나는 자바스크립트에 익숙하다면 이벤트를 쉽게 활용할 수 있다는 것이다.

그러므로 현재 자바스크립트 공부와 리액트공부를 병행하고 있다, 이미 알고 있는 사실이면서도, 책을 읽으며 역시나 자바스크립트의 코어를 단단히 하다는것이 매우 중요하다는걸 알 수 있었다.


리액트를 다루는 기술을 읽고 요약한 글 입니다😊

좋은 웹페이지 즐겨찾기