React 이벤트 핸들러 네이밍은 어떤 방식으로 해야 할까 ?
들어가면서
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 이벤트 핸들러 함수 실행
- 위 예제에서는 각 button 요소에
✅ 상위 - 하위 컴포넌트 관계에서
// 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>
)
}
위에 예제의 경우 다음과 같은 원치 않은 상황이 연출 될 수 있습니다.
props
에는onClick
이름(Built-in 이벤트 이름과 동일한)의 이벤트 핸들러가 있을 것이다.- 개발자가 원했던 상황은
button
요소에만 props 로 전달한 onClick 이벤트 핸들러가 바인딩 되고 이벤트 발생 시 수행되길 원했을 것이다. - 하지만, 모든 props 를 하나의
props
라는 parameter 에 담아서 주었기 때문에div
요소에도 props 가 디스트럭처링 되면서 내부적으로 포함하고 있는 onClick 이벤트 핸들러 또한 적용될 것이다. (onClick={onClick} 형태로..) - 결과적으로 button 을 클릭해서 button 의 onClick 이벤트가 발생했지만, 이벤트 버블링 현상 때문에 div 에 적용되어 있는 onClick 이벤트 또한 실행될 것 입니다.
따라서, 위와 같은 상황을 방지하기 위해서 props 에 담겨 내려올 내용 중 Built-in 이벤트와 이름이 같은 형태가 있을 경우, 이를 파라미터에서 분리하는 것이 일종의 사이드 이펙트를 막을 수 있는 방법입니다.
const MyComponent = ({ props, onClick ) => {
return (
<div {...props}>
<button onClick={onClick}>Button</button>
</div>
)
}
참고 자료