Javascript

이벤트 핸들러를 어떻게 할당해줘야 할까?

학습했던 내용을 정리하기 위해 작성된 글이며 다소 부정확한 내용이 포함될 수 있음을 양해바랍니다.

이미 게시된 글이라도 복습하는 과정에서 내용이 보완 또는 수정될 수 있습니다.

 

 

이벤트 핸들러를 붙여주는 방식엔 크게 3가지가 있다.

//index.html
//첫 번째
<input onclick={handleClick} type="button">

//index.js
//두 번째
button.onclick = function() {...}

//세 번째
button.addEventListener('Click', handleClick1);
button.addEventListener('Click', handleClick2);
button.addEventListener('Click', handleClick3);

속성으로 onClick을 넣어주는 것과 이벤트리스너 메서드를 붙여주는 것은 단지 방식의 차이일 뿐이다. 효율면에서는 큰 차이가 없다. 다만 이벤트리스너를 더 유동적으로 활용할 수 있다. 이벤트리스너를 사용한다면, 한 가지 이벤트에 여러 이벤트 핸들러를 할당할 수 있다는 장점이 있다.

 

리액트를 사용하는 입장이라면, JSX로 작성된 HTML에 핸들러를 할당한다. 일반적으로 기명 함수를 할당한다.

<button type="button" onClick={handleClickReset}>Reset</button>

 

아래처럼, 배열 메서드로 핸들러가 포함된 여러 요소를 생성해야 한다면 익명 함수를 활용한다. 익명 함수를 통해 이벤트 핸들러를 호출하는 셈이다. 익명함수를 거쳐 호출해야 하는 비효율이 발생하지만 더 좋은 방법이 떠오르지 않는다.

{['+', '-', '*', '/', '='].map((i) => (
     <button type="button" onClick={() => handleClickOperator(i)}>
            {i}
     </button>
 ))}

 

만약 익명함수가 핸들러를 호출하는 것이 아니라 직접 이벤트를 처리한다면? 아무 문제없이 작동한다.

{['+', '-', '*', '/', '='].map((i) => (
     <button type="button" onClick={() => { render(i) }}>
            {i}
     </button>
 ))}

그러나 코드의 가독성이 떨어지게 된다. 이벤트 핸들러가 어떤 기능을 하는지 쉽게 파악하기 힘들고 코드의 재사용성도 감소한다. (기명 함수로 할당하는 경우에도, 핸들러를 단순히 onClick이라고 네이밍하는 것은 바람직하지 않다.)

 

정리하자면,

  • 이벤트 핸들러에는 명확한 이름을 지어준다.
  • 기명으로 선언된 함수를 핸들러로 할당한다.
  • 이벤트 객체를 활용해야 하는 경우에는 익명 함수로 이벤트 핸들러를 호출하도록 한다.

한편, 익명 함수로 이벤트 핸들러를 호출하는 방식은 객체에 대한 의존성을 줄여줄 수 있다는 장점이 있다. 만약 기명 함수로서 할당된 이벤트 핸들러가 객체를 인수로 받아 작업을 처리해야 한다면, 같은 유형의 객체에 대해서만 기능할 수 있는 함수로 전락하게 된다. 함수의 범용성이 크게 떨어지는 것이다.

const handleClick = (e) => {
	const {clientX, clientY} = e;
	
	//...
}

button.addEventListener(‘click’, handleClick);

 

같은 경우에, 익명 함수를 통해 객체를 분해하고 함수에 필요한 값만 전달해준다면,

const handleClick = (x, y) => {
	//...
}

button.addEventListener(‘click’, 
	({clientX, clientY}) => handleClick(clientX, clientY));

이벤트 핸들러의 객체에 대한 의존을 끊어버릴 수 있다. 객체의 유형따위는 고려하지 않아도 되고, 단순히 인수로 들어오는 값에 따라 작업을 처리하면 된다. 게다가 내부에서 불필요하게 객체를 구조분해하지 않아도 된다.