React

React event handling

개갑순이돌이짱 2021. 10. 27. 00:45

 

사용자가 웹 브라우저에서 DOM 요소들과 상호 작용하는 것을 이벤트라고 한다.

예를 들어 버튼에 마우스 커서를 올렸을 때는 onmouseover 이벤트를 실행

클릭했을 때는 onclick 이벤트를 실행

form 요소 값이 바뀔 때 onchange 이벤트를 실행

 

리액트의 이벤트 시스템

 

리액트의 이벤트 시스템은 웹 브라우저의 html 이벤트와 인터페이스가 동일하기 때문에

 

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

 

 

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

html의 onclick은 리액트에서는 onClick으로 작성

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

html에서 이벤트를 실행할 때는 큰따음표 안에 실행할 코드를 넣었지만,

리액트에서는 함수 형태의 객체를 전달 앞서 버튼 예제에서도 화살표 함수 문법으로

함수를 만들어서 전달 랜더링 부분 외부에 미리 만들어서 전달해도 됨

3. Dom 요소에만 이벤트를 설정

즉 div, button, input, span, form 등의 DOM 요소에는 이벤트를 설정

우리가 직접 만든 컴포넌트에는 이벤트를 자체적으로 설정할 수 없다.

 

예를 들어 다음과 같이 Mycomponent에 onClick값을 설정한다면 MyComponent를 클릭할 때

doSomething 함수를 실행하는 것이 아니라 그냥 이름이 onClick인 props를 Mycomponent에게 전달

 

<Mycomponent onClick={doSomething}/>

 

전달 받은 props를 컴포넌트 내부의 DOM 이벤트로 설정할 수는 있죠.

<div onClick={this.props.onClick}>
</div>

 

이벤트 종류

-  Clipboard

- Composition

- Focus

- Form

- Mouse

- selection

- Touch

- Wheel

- Media

- Image

- Animation

- Transition

 

예제로 이벤트 핸들링익히기

 

src/EventPractice.js

import React, { Component } from 'react';

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

export default EventPractice;

 

App.js

import EventPractice from "./EventPractice";

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

export default App;

 

 

onChange 이벤트 핸들링하기

 

src/EventPractice.js

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);
                    }
                }
                ></input>
            </div>
        );
    }
}

export default EventPractice;

 

여기서 콘솔에 기록되는 e는 SyntheticEvent로 웹 브라우저의 네이티브 이벤트를 감싸는 객체

네이티브 이벤트와 인터페이스가 같으므로 순수 자바스크립트에서 html 이벤트를 다룰 때와 똑같이 사용

SyntheticEvent는 네이티브 이벤트와 달리 이벤트가 끝나고 나면 이벤트가 초기화되므로 정보를 참조할 수 없다.

 

만약 비동기적으로 이벤트 객체를 참조할 일이 있다면 e.persist() 함수를 호출

 

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.target.value);
                    }
                }
                ></input>
            </div>
        );
    }
}

export default EventPractice;

 

 

state에 input 값 담기

 

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
                        })
                        
                    }
                }
                ></input>
            </div>
        );
    }
}

export default EventPractice;

 

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

 

우리가 입력한 값이 state에 잘들어 갔는지 

input 요소 코드 아래쪽에 button을 하나 만들고

클릭 이벤트가 발생하면 현재 comment 값을 메시지 박스로 띄은 후 commnet 값을 공백으로 설정

 

src/EventPractice.js

 

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

export default EventPractice;

 

임의 메서드 만들기

 

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

 

onCange와 onClick에 전달한 함수를 따로 빼내서 컴포넌트 임의 메서드

 

함수가 호출될 때 this는 호출부에 따라 결정되므로, 클래스의 임의 메서드가 특정 HTML 요소의

이벤트로 등록되는 과정에서 메서드와 this의 관계가 끊어져 버림

임의 메서드가 이벤트로 등록되어도 this를 컴포넌트 자신으로 제대로 가리키기 위해서는

메서드를 this와 바인딩하는 작업이 필요 

만약 바인딩을 하지 않는 경우라면 this가 undefined를 가리킴

 

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

export default EventPractice;

 

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

 

메서드 바인딩은 생성자 메서드에서 하는 것이 정석

새 메서드를 만들때 마다 constructor도 수정해야 함

간단하게 하는 방법은

바벨의 transform-class-properties문법 사용하여 화살표 함수 형태로 메서드를 정의

 

    handleChange = (e) => {
        this.setState({
            message: e.target.value
        });
    }
    handleClick = () =>{
        alert(this.state.message);
        this.setState({
            message:''
        });
    }

 

Input 여러 개 다루기

 

event 객체를 활용

 e.target.name 값을 사용

onChange 이벤트 핸들러에서 e.target.name은 해당 인풋의 name을 가리킨다

지금은 message

이 값을 사용하여 state를 설정하면 쉽게 해결

render 함수에서  name 값이 username인 input를 렌더링해 주었고,

state쪽에도 username이라는 값을 추가

 

 

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>
                
                <input
                type="text"
                name="message"
                placeholder="아무거나 입력해주세요"
                value={this.state.message}
                onChange={
                    this.handleChange
                }
                ></input>
                <button onClick={
                    this.handleClick
                }>확인</button>
            </div>
        );
    }
}

export default EventPractice;

 

 

이것이 핵심

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

    handleChange = (e) => {
        this.setState({
            [e.target.name]: e.target.value
        });
    }

 

예를 들어

const name='admin';
const object = {
	[name]:'value'
}

{
	'admin':'value'
}

 

onKeyPress 이벤트 핸들링

 

comment 인풋에서 Enter키 눌렀을때 handleClick 메서드를 호출

 

 handleKeyPress = (e) =>{
      if(e.key === 'Enter'){
          this.handleClick();
      }
    }
    
         <input
                type="text"
                name="message"
                placeholder="아무거나 입력해주세요"
                value={this.state.message}
                onChange={
                    this.handleChange
                }
                onKeyPress={
                    this.handleKeyPress
                }
                ></input>
                <button onClick={
                    this.handleClick
                }>확인</button>
            </div>

 

 

함수 컴포넌트로 구현해 보기

 

 

import { useState } from "react";

const EventPractice = () =>{
    const [username, setUsername] = useState('');
    const [message, setMesage] = useState('');
    const onChangeUsername = e => setUsername(e.target.value);
    const onChangeMessage = e => setMesage(e.target.value);
    const onClick = () =>{
        alert(username + ':' + message);
        setUsername('');
        setMesage('');
    };
    const onKeyPress= e =>{
        if(e.key === 'Enter'){
            onClick();
        }
    };
    return(
        <div>
        <h1>이벤트 연습</h1>
        <input
        type="text"
        name="username"
        placeholder="사용자명"
        value={this.state.username}
        onChange={
            this.handleChange
        }
        ></input>
        
        <input
        type="text"
        name="message"
        placeholder="아무거나 입력해주세요"
        value={this.state.message}
        onChange={
            this.handleChange
        }
        onKeyPress={
            this.handleKeyPress
        }
        ></input>
        <button onClick={
            this.handleClick
        }>확인</button>
    </div>
    );
};

 

useState를 통해 사용하는 상태에 문자열이 아닌 객체로 넣기

import { useState } from "react";

const EventPractice = () =>{
    const [form, setForm] = useState({
        username:'',
        message:'',
        })
        const { username, message} = form;
    const onChange= e=>{
        const nextForm ={
            ...form, //기존의 form내용을 이자리에 복사 한뒤
            [e.target.name]: e.target.value // 원한은 값을 덮어 씌우기
        };
        setForm(nextForm);
    }
    const onClick = () =>{
        alert(username + ':' + message);
        setForm({
        username:'',
        message:''
        });
    };
    const onKeyPress= e =>{
        if(e.key === 'Enter'){
            onClick();
        }
    };

    
    return(
        <div>
        <h1>이벤트 연습</h1>
        <input
        type="text"
        name="username"
        placeholder="사용자명"
        value={this.state.username}
        onChange={
            this.handleChange
        }
        ></input>
        
        <input
        type="text"
        name="message"
        placeholder="아무거나 입력해주세요"
        value={this.state.message}
        onChange={onChange
        }
        onKeyPress={
            onKeyPress
        }
        ></input>
        <button onClick={
            this.handleClick
        }>확인</button>
    </div>
    );
};