React 이벤트 핸들러 네이밍은 어떤 방식으로 해야 할까 ?

위영민(Victor)·2023년 1월 1일
0

들어가면서

React 로 사이드 프로젝트를 다른 FE 개발자분들과 진행하면서 사전에 여러 컨벤션(커밋 컨벤션, 스타일링 컨벤션 등)을 정합니다. React 에서 이벤트 핸들러 메서드를 정의하고 바인딩하는 것 역시 그 중 하나여도 좋다고 생각합니다. 이번 포스팅에서는 React 커뮤니티에서 일반적으로 알려지고 있는 이벤트 핸들러 네이밍 컨벤션대해 정리해보겠습니다.

기본 네이밍

🔵 Function

  • handle* prefix 를 붙여서 작성합니다.
  • 예를 들어, handleClick
  • handle* 은 이벤트가 발생했을 때 어떤 것이 호출되는지를 의미합니다.

🔵 Props

  • on* prefix 를 붙여서 작성합니다.
  • 예를 들어, onClick
  • on* 은 어떠한 이벤트가 연결된다는 것을 의미합니다.

하나의 컴포넌트 관점에서

🔵 하나의 이벤트만 존재하는 경우

예를 들어, MyComponent 라는 컴포넌트 내부에서 button 요소에 onClick 이벤트가 하나만 존재한다는 전제하에 이벤트를 바인딩 한다면.

const MyComponent = () => {
  
	const handleClick = () => {
  	console.log('button Clicked !!');
	}

	return <button type="button" onClick={handleClick}>...</button>  
}

기본적으로 제공하는 onEvent 형식에 맞게 이벤트 핸들러 함수도 handleEvent 형식으로 사용합니다.

🔵 하나의 이벤트가 여러 개 존재하는 경우

이번에는 MyComponent 내부에 여러 개의 onClick 이벤트가 존재하는 경우를 봅시다.

const MyComponent = () => {
  
  const handleButtonOneClick = () => {
    console.log("button-one Click !!");
  }
  
  const handleButtonTwoClick = () => {
    console.log("button-two Click !!");
  }
  
  const handleButtonThreeClick = () => {
    console.log("button-three Click !!");
  }
	
  // 각각의 버튼은 다른 기능을 한다고 가정
	return (
    <>
  		<button type="button" name="button-one" onClick={handleButtonOneClick}>...</button>
    	<button type="button" name="button-two" onClick={handleButtonTwoClick}>...</button>
    	<button type="button" name="button-three" onClick={handleButtonThreeClick}>...</button>
  	</>
  )
}

위 예시에서는 MyComponent 내부적으로는 button 요소가 3개가 존재하며 각각은 onClick 이벤트가 존재합니다.

그렇다면, 위에서 언급한 onEvent - handleEvent 규칙을 지키기가 어렵습니다. (각 이벤트 발생 시, 다른 기능이 작동하기 때문)

이런 경우는 handleComponentEvent 형식을 적용해볼 수 있습니다.
위 예제에서는 각 button 요소에 name 속성으로, 서로 다른 컴포넌트라는 것을 가정했습니다.

똑같은 button 요소에 대해 onClick 이벤트가 발생하지만, 각 클릭 이벤트에 바인딩된 이벤트 핸들러 함수는 각각 handleComponentEvent 규칙이 적용된 형태인 것을 확인할 수 있습니다.

  • button-one 버튼 -> onClick 이벤트 발생 시 -> handleButtonOneClick 이벤트 핸들러 함수 실행
  • button-two 버튼 -> onClick 이벤트 발생 시 -> handleButtonTwoClick 이벤트 핸들러 함수 실행
  • button-three 버튼 -> onClick 이벤트 발생 시 -> handleButtonThreeClick 이벤트 핸들러 함수 실행

상위 - 하위 컴포넌트 관계에서

// Counter 컴포넌트(상위)
const Counter = () => {
  const [count, setCount] = useState(0);
  
  // 실질적인 UI or 비즈니스 로직을 처리하는 이벤트 핸들러
  // 컴포넌트의 이벤트 관련된 파라미터들은 없고, 로직에 필요한 데이터만 받는다.
  const handleCountChange = (offset) => {
    setCount(count + offset)
  }
  
  return (
  	<>
    	<span>{count}</span>
    	<BottonMinus onCountChange={handleCountChange} />
    	<BottonPlus onCountChange={handleCountChange} />
  	</>
  )
}

// ButtonPlus 컴포넌트(하위)
const ButtonPlus = ({ onCountChange }) => {
  
  // 특정 컴포넌트에 바인딩한 이벤트가 발생했을 때 수행되는 이벤트 핸들러
  // props 로 받을 UI or 비즈니스 로직을 담당하는 이벤트 핸들러들이 수행된다.
  const handlePlusButtonClick = (event) => {
   	onCountChange(event.target.value);
  }
  
  return <button type="button" value={1} onClick={handlePlusButtonClick}>+</button>
}

// ButtonMinus 컴포넌트(하위)
const ButtonMinus = ({ onCountChange }) => {
  
  // 특정 컴포넌트에 바인딩한 이벤트가 발생했을 때 수행되는 이벤트 핸들러
  // props 로 받을 UI or 비즈니스 로직을 담당하는 이벤트 핸들러들이 수행된다.
  const handleMinusButtonClick = (event) => {
    onCountChange(event.target.value);
  }
  
  return <button type="button" value={-1} onClick={handleMinusButtonClick}>-</button>
}

정리하자면

  • props 로 전달받는 이벤트 핸들러는 onTargetEvent 형식으로 넘겨주고(상위 컴포넌트 입장) 받습니다(하위 컴포넌트 입장).
  • UI 나 비즈니스 로직을 수행할 이벤트 핸들러 함수의 경우 handleTargetEvent 형식으로 정의합니다.
  • 이벤트가 적용될 컴포넌트에 바인딩하는 이벤트 핸들러 함수의 경우 handleComponentEvent 형식으로 정의합니다.

주의할 점 - 기본으로 제공되는 핸들러 이름 사용 시(Using Built-in Handler Name)

const MyComponent = (props) => {
  return (
  	<div {...props}>
      <button onClick={props.onClick}>Button</button>
  	</div>
  )
}

위에 예제의 경우 다음과 같은 원치 않은 상황이 연출 될 수 있습니다.

  1. props 에는 onClick 이름(Built-in 이벤트 이름과 동일한)의 이벤트 핸들러가 있을 것이다.
  2. 개발자가 원했던 상황은 button 요소에만 props 로 전달한 onClick 이벤트 핸들러가 바인딩 되고 이벤트 발생 시 수행되길 원했을 것이다.
  3. 하지만, 모든 props 를 하나의 props 라는 parameter 에 담아서 주었기 때문에 div 요소에도 props 가 디스트럭처링 되면서 내부적으로 포함하고 있는 onClick 이벤트 핸들러 또한 적용될 것이다. (onClick={onClick} 형태로..)
  4. 결과적으로 button 을 클릭해서 button 의 onClick 이벤트가 발생했지만, 이벤트 버블링 현상 때문에 div 에 적용되어 있는 onClick 이벤트 또한 실행될 것 입니다.

따라서, 위와 같은 상황을 방지하기 위해서 props 에 담겨 내려올 내용 중 Built-in 이벤트와 이름이 같은 형태가 있을 경우, 이를 파라미터에서 분리하는 것이 일종의 사이드 이펙트를 막을 수 있는 방법입니다.

const MyComponent = ({ props, onClick ) => {
  return (
  	<div {...props}>
      <button onClick={onClick}>Button</button>
  	</div>
  )
}

참고 자료

profile
🌟 Let the brighter shine the brighter.

0개의 댓글