Let's Write_ 프론트엔드

'react이벤트핸들러'에 해당되는 글 1건

  1. React - event handler 이벤트 핸들러의 e 는 어떻게 전달되는 걸까?

React - event handler 이벤트 핸들러의 e 는 어떻게 전달되는 걸까?

TIL

처음 공부를 시작할 때 이해가 잘 안 되는 부분이 있었는데 바로 이벤트 핸들러 함수를 정의할 때의 e 였다.

 

예를 들면 아래에서의 handleSubmit(e) 함수 정의가 있다.

function Form() {
  function handleSubmit(e) {
    e.preventDefault();
    console.log('You clicked submit.');
  }

  return (
    <form onSubmit={handleSubmit}>
      <button type="submit">Submit</button>
    </form>
  );
}

 

onSubmit에서 e는 등장한 적이 없는데 handleSubmit 은 대체 어떻게 e를 받는 거지?

 

이런 의문을 나만 가졌을 리 없다.

 

누군가에게 도움이 되길 바라며 적는 글이다.

 

[TOC]
# 1 . 결론
# 2. 자바스크립트
## 2.1 addEventListener
## 2.2 DOM Spec
## 2.3 listener callback
# 3. React
## 3.1 React listener
## 3.2 Synthetic Event

 

 

결과적으로 기억할 내용은 다음이다.

# 1. 결론

React 에서 JSX 에 이벤트핸들러로 넘기는 이벤트리스너함수(콜백)는 return/render 전에 정의하고, 이벤트에 걸리는 이벤트 리스너는 인자로  해당synthetic event 를 받을 수 있다.

 

이유에 대한 결론은 만들어진 곳에서 넘겨받은 함수는 첫번째 인자로 e(이벤트) 를 받아 호출할 수 있게 정의해 뒀기 때문이다.

호출되는 곳에서는 콜백함수에 인자로 이벤트 객체를 넘기고 넘겨질 콜백함수는 개발자가 정의, 선언하는데
그 때 정의 하는 인자의 네이밍은 e, event,evt 등등 쓰는 사람 마음대로 적혀지곤 한다.
그러나 최고의 네이밍은 누가 봐도, 코딩을 모르는 사람이 봐도 읽을 수는 있는 event 로 적는 것이 가독성과 협업성에 좋으니까 event로 는게 좋다.

 

라고 경험 + 공식문서 내용으로 알 수 있는데 좀 더 파헤쳐 보자.

 

React는  javascript 라이브러리 라는 걸 먼저 기억하자.

 

# 2. 자바스크립트

## 2.1 addEventListener

 

javascript 에서는

EventTarget.addEventListener()

를 이용해서 돔에서 발생하는 이벤트를 잡아 콜백 함수를 설정할 수 있다.

(EventTarget의 addEventListener() 메서드는 지정한 이벤트가 대상에 전달될 때마다 호출할 함수를 설정합니다.)

 

참고로 콜백 함수란, 함수의 인자로 보낼 수 있는 함수로 생각하면 이해하기 쉽다.

 

사용 구문은 다음과 같다.

target.addEventListener(type, listener[, options]);
target.addEventListener(type, listener[, useCapture]);

 

1. 사용할 때 필수적으로 와야 하는 첫 번째 인자 type이란

이벤트의 유형으로 'click', 'submit', 'focus'  등 w3c에서 정의한  이벤트 종류이다.

 

2.  필수적으로 와야 하는 두 번째 인자 listner

앞에서 정의한 이벤트 type의 이벤트가 발생했을 때 실행될 콜백 함수로,

('click' -> 'click' event)를 첫 번째 인자로 받는 함수이다. => 요 리스너가 리액트의 리스너와 같은 역할이다.

 

그리고 관련하여 돔 명세를 봐보자


## 2.2 DOM Spec

obj.addEventListener("load", imgFetched)

function imgFetched(ev) {
  // great success
  …
}
 In the example above ev is the event. ev is passed as an argument to the event listener’s callback (typically a JavaScript Function as shown above). Event listeners key off the event’s type attribute value ("load" in the above example). The event’s target attribute value returns the object to which the event was dispatched (obj above).

 

돔명세에 의하면 이벤트 리스너의 콜백에는 이벤트가 소괄호 안에 argument 로 전달된다.

e든 ev든 evt, event 든 identifier 일 뿐 그 자리에는 이벤트가 들어온다.

 


## 2.3 listener callback

addEventListener 에 오는  콜백함수 형태를 보면

1. function(e) { ...}

2. function(){...}

이런 익명함수들인데,

인자가 없는 건, 함수 내에서 e 를 참조할 필요가 없을 때 굳이 넘겨받지 않아도 되기때문에 인자로도 안받는 것이다.

이 부분이 포인트다.

 

이 부분의 이해를 돕는 예시를 만들어 봤다.

function log(a) {
    console.log(a)
}
log('test') // test
log('test', 2) // test

function alarm(msg){
  alert("!");
}
alarm(msg) // !
alarm() // !

function alarm2(){
  alert("!");
}
function alarm2(123) // !

 

그리고 event.target 은 이벤트가 발생한 객체이다.

 

 이벤트 타겟의 명세는 다음과같다

 

2.7. Interface EventTarget

[Exposed=(Window,Worker,AudioWorklet)]
interface EventTarget {
  constructor();

  undefined addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options = {});
  undefined removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options = {});
  boolean dispatchEvent(Event event);
};

callback interface EventListener {
  undefined handleEvent(Event event);
};

dictionary EventListenerOptions {
  boolean capture = false;
};

dictionary AddEventListenerOptions : EventListenerOptions {
  boolean passive = false;
  boolean once = false;
  AbortSignal signal;
};

 

 

# 3. React

자바스크립트에서는 addEventListener를 통해서 이벤트 핸들러를 구현하지만, 리엑트에서는 다르다. 


## 3.1 React listener

When using React, you generally don’t need to call  'addEventListener' to add listeners to a DOM element after it is created. Instead, just provide a listener when the element is initially rendered.

React에서는  DOM element가 생성된 "후"에 리스너를 추가하기 위해 addEventListener를 호출할 필요가 없습니다.  처음 렌더링 될 때 리스너를 제공합니다.

이는 return 위에서 정의한 handleSubmit 함수의 위치를 의미하는 듯하다.

다시 말하자면 리스너는 이벤트가 발생할 때 실행될 콜백 함수이다.

이 콜백 함수를 return 위에서 작성해 주는 것이 react의 방식이다.


## 3.2 Synthetic Event

리액트에서는 합성이벤트 (Synthetic Event) 라는 리액트 이벤트를 사용하는데 이건 브라우저에서 기본적으로 제공하는 

native event 를 참고해서 리액트에서 재가공한 이벤트 객체이다.

이벤트 핸들러는 모든 브라우저에서 이벤트를 동일하게 처리하기 위한 이벤트 래퍼 SyntheticEvent 객체를 전달받습니다. 
Although events are typically dispatched by the user agent as the result of user interaction or the completion of some task, applications can dispatch events themselves by using what are commonly known as synthetic events:
이벤트는 일반적으로 사용자 상호 작용 또는 일부 작업 완료의 결과로 사용자 에이전트에 의해 전달되지만 어플리케이션은 일반적으로 합성 이벤트로 알려진 것을 사용하여 이벤트를 전달할 수 있습니다.

// add an appropriate event listener
obj.addEventListener("cat", function(e) { process(e.detail) })
// create and dispatch the event  [ synthetic event ]  <- 요걸 리액트에서 쓴다
var event = new CustomEvent("cat", {"detail":{"hazcheeseburger":true}}) obj.dispatchEvent(event)

 

따라서 JS DOM 에 정의된 이벤트와는 정확히 일치하지는 않는다. 

 

 

 

 

https://developer.mozilla.org/ko/docs/Web/API/EventTarget/addEventListener

https://developer.mozilla.org/ko/docs/Web/API/EventListener

https://developer.mozilla.org/en-US/docs/Web/API/EventListener/handleEvent

https://ko.reactjs.org/docs/events.html 

 

https://dom.spec.whatwg.org/#introduction-to-dom-events

https://dom.spec.whatwg.org/#interface-eventtarget