다라다라V
article thumbnail
728x90
반응형

이벤트(event)란 사용자가 웹 브라우저에서 DOM 요소들과 상호작용하는 것을 의미합니다. 3장에서 사용했던 마우스 클릭이나 마우스 커서 올리기, 입력 등등이 이벤트의 예시입니다.

html의 alert와 같이 사용자가 웹 브라우저에서 상호작용하는 것이 이벤트(event)입니다. 리액트의 이벤트는 순수 JavaScript 혹은 jQuery를 사용한 웹 어플리케이션에서 이벤트를 다루는 것과 동일합니다. 기존 HTML DOM Event를 알고 있다면 리액트의 컴포넌트도 쉽게 다룰 수 있을 것입니다. 클래스형 컴포넌트 함수형 컴포넌트에서 이벤트를 다루도록 합시다

 


📚 이벤트를 사용할 때 주의사항

1. 이벤트 이름은 카멜 표기법으로 작성합니다.

  • HTML의 onclick은 리액트에서 onClick으로 작성
  • onekeyup은 onKeyUp으로 작성

 

2. 이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아닌 함수 형태의 값을 전달

  • HTML에서는 이벤트를 설정할 때 큰따옴표 안에 실행할 코드를 넣음
  • 리액트에서는 함수 형태의 객체를 전달
  • 화살표 함수 문법 처럼 바로 만들어서 전달해도 되고, 렌더링 부분 외부에 미리 만들어서 전달해도 가능

 

3. DOM 요소에만 이벤트를 설정할 수 있음

  • div, button, input, form, span 등의 DOM 요소에는 이벤트를 설정할 수 있음
  • 그러나 자신이 직접 만든 컴포넌트에는 이벤트를 자체적으로 설정할 수 없음
  • 전달받은 props를 컴포넌트 내부의 DOM 이벤트로 설정할 수는 있음

📚 이벤트 종류

리액트에서 지원하는 이벤트 종류는 다음과 같습니다. 리액트 메뉴얼(https://facebook.github.io/react/docs/event.html)을 참고하여 이벤트들에 대한 자세한 설명들을 볼 수 있습니다.

  • Clipboard
  • Keyboard
  • Form
  • Selection
  • UI
  • Media
  • Animation
  • Image
  • Wheel
  • Touch
  • Mouse
  • Focus
  • Composition

 

실습할 단계는 다음과 같습니다.

  1. 컴포넌트 생성 및 불러오기
  2. onChange 이벤트 핸들링하기
  3. 임의 메서드 만들기
  4. input 여러개 다루기
  5. onKeyPress 이벤트 핸들링하기

 

📃 컴포넌트 생성

src 디렉터리 내부에 EventPractice.js 파일을 만들어 기능을 구현해보겠습니다.

// EventPractice.js
import {Component} from 'react';

class EventPractice extends Component {
    render() {
        return (
            <div>
                <h1>이벤트 연습</h1>
            </div>
        );
    }
}

export default EventPractice;

 

📃 App.js에서 EventPractice 렌더링  

App 컴포넌트에서 EventPractice를 불러와 렌더링하면 이벤트 연습 화면이 렌더링된 화면을 볼 수 있습니다.

// App.js
import EventPractice from "./EventPractice";

const App = () => {
  return <EventPractice />;
};

export default App;

📃 onChange 이벤트 설정

EventPractice 컴포넌트에 input 요소를 렌더링하는 코드와 해당 요소에 onChange 이벤트를 설정하는 코드를 작성합니다.

// EventPractice.js

import {Component} from 'react';

class EventPractice extends Component {
    render() {
        return (
            <div>
                <h1>이벤트 연습</h1>
                <input
                    type="text"
                    name="message"
                    onChange={
                        (e) => {
                            console.log(e);
                        }
                    }
                />
            </div>
        );
    }
}

export default EventPractice;

이러한 코드를 작성하고 웹 브라우저에서 크롬 개발자 도구(F12) console을 열어 인풋에 입력할 수 있습니다.

  • 콘솔에 기록되는 e 객체는 SyntheticEvent로 웹 브라우저의 네이티브 이벤트(브라우저 고유 이벤트)를 감싸는 객체
  • SyntheticEvent는 네이티브 이벤트와 달리 이벤트가 끝나고 초기화 되어 정보를 참조할 수 없음
  • 비동기적으로 이벤트 객체를 참조할 일이 있다면 e.persist( ) 함수를 호출해야함

 

📃 state에 input 값 담기 

state에 input 값을 담겠습니다. 생성자 메서드 constructor에서 state 초깃값을 설정하고, 이벤트 핸들링 함수 내부에서 this.setState 메서드를 호출하여 state를 업데이트 할 수 있습니다.

* state에 대한 내용은 3장(https://daradarav.tistory.com/14)을 참고하세요

// 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) => {
                            this.setState({
                                message: e.target.value
                            })
                        }
                    }
                />
            </div>
        );
    }
}

export default EventPractice;

input에 아무거나 입력하여 오류가 발생하지 않으면 잘 담겨진 것입니다.

 

📃 버튼을 누를 때 comment 값을 공백으로 설정

input 요소 코드 아래 쪽에 button을 하나 만들고, 클릭 이벤트가 발생하면 현재comment 값을 메시지 박스로 띄운 후 comment 값을 공백으로 설정합니다. alert를 사용하여 현재 message 값을 화면에 표시합니다.

// EventPractice.js
import {Component} from 'react';

class EventPractice extends Component {
    
    state = {
        message: ""
    }
    
    render() {
        return (
            <div>
                <h1>이벤트 연습</h1>
                ( ... )
                <button onClick={
                    () => {
                        alert(this.state.message);
                        this.setState({
                            message: ""
                        });
                    }
                }>확인</button>
            </div>
        );
    }
}

export default EventPractice;

📃 기본 방식

앞선 리액트 이벤트 사용시 주의사항 1번에서 수 형태의 객체 값을 전달한다고 배웠습니다. 이벤트를 처리할 때 렌더링 하는 동시에 함수를 작성할 수도 있지만, 함수를 미리 준비하여 전달하는 방법도 있습니다. onChange onClick에 전달한 함수를 따로 빼내서 컴포넌트 임의 메서드를 만들겠습니다.

// EventPractice.js
import {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;
  • 함수가 호출될 때 this는 호출부에 따라 결정
  • 클래스의 임의 메서드가 특정 HTML 요소의 이벤트로 등록되는 과정에서 메서드와 this의 관계가 끊어짐
  • 임의 메서드가 이벤트로 등록되어도 this를 컴포넌트 자신으로 제대로 가리키기 위해서는 메서드를 this와 바인딩하는 작업이 필요
  • 바인딩하지 않는 경우라면 this가 undefined를 가리킴
  • 위 코드에서는 constructor 함수에서 함수를 바인딩하는 작업을 함

 

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

기본 작업은 새 메서드를 만들 때 마다 constructor를 수정해야 하기 때문에 불편합니다. 이 작업을 간단하게 하려면 바벨의 transfor-class-properties 문법을 사용하여 화살표 함수 형태로 메서드를 정의할 수 있습니다.

// EventPractice.js
import {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;

📃 input 여러 개  다루기

input이 여러 개일 때는 event 객체를 이용하여 e.target.name의 값을 사용합니다. onChange 이벤트 핸들러에서 e.target.name은 해당 input의 name을 가리킵니다. 

// EventPractice.js
import {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;
  • e.target.name은 해당 인풋의 name을 가리키므로 현재 코드에서는 message 
  • render 함수에서 name 값이 username인 input을 렌더링
  • state 쪽에도 username이라는 값이 추가

📃 onKeyPress 이벤트 핸들링

키를 눌렀을 때 발생하는 KeyPress 이벤트를 처리하는 방법을 알아보겠습니다. comment 인풋에서 엔터를 눌렀을 때 handleClick 메서드를 호출하도록 하는 코드입니다.

// EventPractice.js
import {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: ""
        });
    }

    handleKeyPress = (e) => {
        if(e.key === 'Enter') {
            this.handleClick();
        }
    }

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

export default EventPractice;

기존의 클래스형 컴포넌트로 구현된 것은 함수형 컴포넌트로도 선언할 수 있습니다.

// EventPractice.js
import {useState} from 'react';

const EventPractice = () => {
    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"
                placeholder="사용자명"
                value={username}
                onChange={onChangeUsername}
            />
            <input
                type="text"
                name="message"
                placeholder="아무거나 입력해보세요"
                value={message}
                onChange={onChangeMessage}
                onKeyPress = {onKeyPress}
            />
            <button onClick={onClick}>확인</button>
        </div>
    );
};

export default EventPractice;
  • e.target.name을 활용하지 않고 onChange 관련된 함수를 따로 두 개 만듦
  • 인풋의 개수가 많아지지 않는다면 e.target.name을 사용하지 않고 따로 함수를 작성해도 됨

 

반응형

'프레임워크 > REACT' 카테고리의 다른 글

[React] 06. 컴포넌트 반복  (0) 2022.11.07
[React] 05. ref:DOM에 이름 달기  (0) 2022.11.01
[React] # 클래스형 컴포넌트 VS 함수형 컴포넌트  (0) 2022.10.21
[React] 03. 컴포넌트  (2) 2022.10.15
[React] 02. JSX  (0) 2022.10.09
profile

다라다라V

@DaraDaraV

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!