# event

## Event 처리

이벤트를 처리하기 위해서는 함수가 필요하며, 클래스 컴포넌트에 함수를 배치하는 방법은 여러 가지가 존재한다.

* 화살표 함수(Arrow function)
* 클래스 메소드 지정
* Function.prototype.call() / .apply()
* Function.prototype.bind()
* Babel transform-class-properties 문법

### Arrow function

화살표 함수로 이벤트를 처리할 경우 다음과 같이 작성한다. 다음 JSX 코드는 버튼을 클릭할 경우 알림창이 출력되는 코드이다.

```jsx
<button onClick={()=>{window.alert('click event')}}>click</button>
```

추가 메소드를 구현하지 않아도 되므로 인라인으로 간편하게 처리할 수 있으나, 코드가 길어지면 가독성이 떨어지므로 간단한 코드 작성 시 유리하다. Arrow function 내에서 this라는 키워드를 사용할 경우 해당 컴포넌트 객체에 접근할 수 있다.

```jsx
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>React CDN Example</title>
    
</head>
<body>

    <div id="app"></div>
    
    <!-- 개발용 CDN -->
    <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

    <!-- 배포용 CDN -->
    <!-- <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script> -->
    <!-- <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script> -->

    <!-- 바벨 CDN(using JSX) -->
    <script src=" https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="text/babel">
        class MainComponent extends React.Component {
            render(){
                return (
                    <>
                        <button onClick={()=>{ alert('click event') }}>click</button>
                    </>
                );
            }
        }

        const app = ReactDOM.createRoot(document.querySelector("#app"));
        app.render(
            <MainComponent/>
        );
    </script>
</body>
</html>
```

{% embed url="<https://codepen.io/hiphop5782/pen/ZERboWO>" %}

### 클래스 메소드 지정

React Component Class 내부에 메소드를 만들고 이를 지정하여 호출할 수 있다.

```jsx
class MainComponent extends React.Component {

    clickEventProcessor(){
        window.alert('click event');
    }

    render(){
        return (
            <>
                <button onClick={this.clickEventProcessor}>click</button>
            </>
        );
    }
}
```

{% embed url="<https://codepen.io/hiphop5782/pen/rNKOvLj>" %}

{% hint style="info" %}

### 클래스 메소드로 이벤트를 처리할 경우 문제점

위와 같이 클래스에 생성한 메소드로 이벤트를 처리할 경우 react component에 접근할 수 없다. <mark style="color:red;">**this**</mark>가 **undefined**로 출력되며, state, props 등 컴포넌트의 다른 구성요소에 접근할 수 없어 컴포넌트와 상관 없는 작업만 처리할 수 있다.

```jsx
class MainComponent extends React.Component {
    clickEventProcessor(){
        console.log(this);
    }
    render(){
        return (
            <>
                <button onClick={this.clickEventProcessor}>click</button>
            </>
        );
    }
}
```

{% endhint %}

### Function.prototype.call() / .apply()

Function에서 제공하는 call 함수와 apply 함수를 이용하면 this를 설정하며 함수 호출이 가능하다. 이를 이용하여 다음과 같이 이벤트를 설정할 수 있다.

```jsx
class MainComponent extends React.Component {
    
    clickEventProcessor(){
        console.log(this);
        window.alert('click event');
    }
    
    render(){
        return (
            <>
                <button onClick={()=>this.clickEventProcessor.call(this)}>click</button>
                <button onClick={()=>this.clickEventProcessor.apply(this)}>click</button>
            </>
        );
    }
}
```

{% embed url="<https://codepen.io/hiphop5782/pen/OJEWKpX>" %}

{% hint style="info" %}
**Function.prototype.call()**&#xACFC; **Function.prototype.apply()**&#xB294; 동일한 기능을 수행하지만 다음 차이가 있다.

* **Function.prorotype.apply()**&#xB294; 인수를 배열로 전달한다.
* **Function.prototype.call()**&#xC740; 인수를 그대로 전달한다.
  {% endhint %}

### Function.prototype.bind()

Function.prototype.bind()를 사용하여 이벤트 처리 함수를 재할당 하여 사용하는 방법이 있다.

```jsx
class MainComponent extends React.Component {

    constructor(){
        super();

        this.clickEventProcessor = this.clickEventProcessor.bind(this);
    }

    clickEventProcessor(){
        console.log(this);
        window.alert('click event');
    }

    render(){
        return (
            <>
                <button onClick={this.clickEventProcessor}>click</button>
            </>
        );
    }
}
```

핵심 코드는 생성자(constructor)에 있는 bind 코드이다.

```jsx
this.clickEventProcessor = this.clickEventProcessor.bind(this);
```

clickEventProcessor에 this를 설정하여 재할당 한 뒤 사용하면 정상적으로 이벤트 함수에서 this가 MainComponent로 출력된다.

{% embed url="<https://codepen.io/hiphop5782/pen/jOKygaG>" %}

### Babel class-transform-properties

Babel에서 제공하는 변환 코드를 사용하여 [#function.prototype.bind](#function.prototype.bind "mention") 대신 사용할 수 있다. 다음과 같은 형태로 이벤트 처리 메소드를 작성한다.

```jsx
class MainComponent extends React.Component {

    constructor(){
        super();
    }

    clickEventProcessor = ()=>{
        console.log(this);
        window.alert('click event');
    }

    render(){
        return (
            <>
                <button onClick={this.clickEventProcessor}>click</button>
            </>
        );
    }
}
```

{% hint style="info" %}
주의사항은 처리 함수는 반드시 화살표 함수로 작성해야 하며, 다음과 같이 작성하면 안된다는 것이다.

```jsx
clickEventProcessor = function(){
    console.log(this);
    window.alert('click event');
}
```

{% endhint %}

실행하면 정상적으로 출력되는  것을 확인할 수 있다.

{% embed url="<https://codepen.io/hiphop5782/pen/bGKqGob>" %}

## 결론

이벤트 처리는 다음과 같은 방법으로 한다.

* 간단한 이벤트 처리 - [#arrow-function](#arrow-function "mention")
* 복잡한 이벤트 처리 - [#babel-class-transform-properties](#babel-class-transform-properties "mention")

지원하는 이벤트의 종류는 다음과 같다.

* Clipboard
* Composition
* Keyword
* Focus
* Form
* Generic
* Mouse
* Pointer
* Selection
* Touch
* UI
* Wheel
* Media
* Image
* Animation
* Transition
* ETC

{% embed url="<https://ko.reactjs.org/docs/events.html#supported-events>" %}
