JavaScript와 React에서의 이벤트(event) 처리 방식

두밥비·2025년 4월 27일

article

목록 보기
10/23
post-thumbnail

서론

이 글은 소플의 처음 만난 리액트 강의를 수강하고 작성한 글입니다.

이벤트는 사용자의 특정 행동(버튼 클릭, 키 입력 등)에 반응하는 중요한 요소입니다. JavaScript DOM 이벤트와 React 이벤트는 이벤트 이름 표기법, 함수 전달 방식, 그리고 this 바인딩에서 차이를 보입니다. 이 글에서는 이러한 차이점과 함께 bind 메서드, this 키워드의 사용법, 클래스 및 함수 컴포넌트에서 이벤트 핸들러를 구현하는 방법을 자세히 다뤄 보겠습니다.

Event?

프로그래밍에서의 Event - 사건
ex) 사용자가 버튼을 클릭한 사건 → 버튼 클릭 이벤트


✏ DOM의 Event vs React의 Event


1) DOM의 Event

<button onclick="activate()">
  Activate
</button>

2) 리액트의 Event

<button onClick={activate}>
  Activate
</button>
비교Dom의 Event리액트의 Event
이벤트 이름 표기법onclickonClick(카멜 표기법)
함수 전달 방식문자열로 전달함수 그대로 전달

→ DOM과 React 모두 Event가 있지만, 사용하는 방법이 조금 다릅니다! 둘 다 사용자 입력(클릭, 입력 등)에 반응한다는 점은 같습니다.


📝 camelCase(카멜 표기법)


카멜 표기법(Camel Case)은 프로그래밍 및 식별자 이름 작성 규칙 중 하나로, 다양한 프로그래밍 언어 및 플랫폼에서 사용되는 네이밍 규칙 중 하나입니다. 카멜 표기법의 주요 특징은 다음과 같습니다

  1. 단어의 첫 글자는 소문자로 시작합니다.
  2. 두 번째 단어부터는 첫 글자를 대문자로 표기합니다.
  3. 단어 사이에는 공백이나 특수 문자가 없고, 단어들을 연결하여 작성합니다.

특징

  • 등에 있는 혹 → C
  • 첫 글자는 소문자, 중간에 나오는 새로운 글자의 첫 글자는 대문자로 시작

카멜케이스(CamelCase) 사용 이유

  1. 가독성 향상: 여러 단어를 이어 붙일 때 각 단어의 첫 글자를 대문자로 구분해 읽기 쉽도록 함
  2. 공백 대체: 프로그래밍 언어에서는 변수나 함수 이름에 공백을 사용할 수 없기 때문
  3. 일관성: 다양한 언어와 프레임워크에서 표준 네이밍 규칙으로 사용됨
  4. 명확성: 변수, 함수, 클래스 이름을 직관적으로 표현 가능
  5. 키워드와 구분: 언어의 예약어와 변수명이 혼동되지 않도록 예방

bind 메서드 설명

bind()는 함수의 this 값을 명시적으로 설정하고, 새로운 함수를 반환하며, 객체 메서드를 다른 객체에 할당하거나, this 값을 고정하기 위해 사용

const boundFunction = originalFunction.bind(thisArg, arg1, arg2, ...);
  • thisArg: 함수 실행 시 this로 사용할 값
  • 새로운 함수는 원래 함수와 달리 this가 고정됨
  • 즉시 실행되지 않고, 나중에 호출할 수 있음
const obj = { value: 42 };
function showValue() { console.log(this.value); }
const boundFunc = showValue.bind(obj);
boundFunc(); // 출력: 42

활용 사례

  • 이벤트 핸들러에서 this 문제 해결
  • 특정 객체 컨텍스트에서 함수 호출

📎 Event Handler(Event Listener)


어떤 사건이 발생했을 때 해당 사건을 처리하는 역할

사용자 이벤트(예: 클릭, 키 입력, 마우스 이동 등)에 대한 응답으로 실행되는 함수

  • 사용법: React에서 이벤트 핸들러는 JSX에서 onClick, onChange 등과 같은 속성에 연결됨
  • this 바인딩 문제: 클래스 컴포넌트에서 this가 자동으로 이벤트 핸들러에 바인딩되지 않음
  • 해결 방법: constructor에서 bind(this)로 명시적 바인딩하거나, 클래스 필드 문법으로 arrow function을 사용함
  • 예시
this.handleClick = this.handleClick.bind(this);

handleClick = () => { /* 함수 내용 */ };
  • 의미: 이벤트 핸들러는 컴포넌트 상태(state) 및 속성(props)에 접근하여 UI를 동적으로 업데이트할 수 있음

클래스 컴포넌트

class Toggle extends React.Component {
  constructor(props) {
    super(props);

    this.state = { isToggleOn: true };

    // callback에서 'this'를 사용하기 위해서는 바인딩을 필수적으로 해줘야 합니다.
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? '켜짐' : '꺼짐'}
      </button>
    );
  }
}
  • 핸들 클릭 함수 정의: 일반 함수처럼 괄호와 중괄호로 클래스 함수 정의
  • 바인딩 필요성: this.handleClick을 constructor에서 bind로 연결해야 함
    • JavaScript 클래스 함수는 기본적으로 this가 바인딩되지 않기 때문
  • 문제점: 바인딩하지 않으면 this.handleClick이 글로벌 스코프에서 undefined로 처리됨
  • 결론: bind를 통해 this를 명확하게 바인딩해야 함수가 올바르게 동작

자바스크립트에서 this의 의미

자바스크립트 내에서 this는 말 그대로 ‘이것’이라고 합니다. 더 쉽게 말하자면 '누가 나를 불렀느냐'를 뜻한다고 합니다.
즉, 선언이 아닌 호출에 따라 달라진다는 겁니다.

“this는 호출 방식, 함수 유형, 실행 컨텍스트에 따라 달라진다.“


  • 일반 함수: this는 함수를 호출한 객체를 가리킴. (window 또는 undefined – 엄격 모드에서)
  • 메서드: this는 해당 메서드를 호출한 객체를 참조함.
  • Arrow function: this는 정의된 위치의 상위 스코프에서 this를 상속받음.
  • 클래스: this는 생성된 인스턴스 객체를 가리킴.
  • 이벤트 핸들러: this는 이벤트가 바인딩된 DOM 요소 또는 클래스 인스턴스를 참조해야 하며, 명시적으로 bind 또는 Arrow function을 사용해 설정해야 함.

만약 bind 사용이 번거롭거나 복잡하게 느껴진다면?

1. Class fields syntax 사용

class MyButton extends React.Component {
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        클릭
      </button>
    );
  }
}

클래스 내부에서 변수를 선언할 수 있는 문법

“클래스 변수를 명확하게 정의”

사용법

class Example {
field = 'value';
}

특징

  • 인스턴스 필드를 클래스 본문에 직접 선언 가능
  • 초기값을 설정할 수 있음
  • 화살표 함수와 함께 사용하여 this 바인딩 문제 해결 가능

2. Arrow function 사용

class MyButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    // 이렇게 하면 'this'가 바운드됩니다.
    return (
      <button onClick={() => this.handleClick()}>
        클릭
      </button>
    );
  }
}
class Example {
	handleClick = () => {
	console.log(this);
	};
}
  • 특징
    • 화살표 함수는 this를 클래스 인스턴스에 자동으로 바인딩.
    • bind(this)를 명시적으로 사용할 필요 없음.
    • 주로 이벤트 핸들러에서 사용됨.

함수 컴포넌트

위에서 본 Toggle 컴포넌트(클래스 컴포넌트)를 함수 컴포넌트로 변환

function Toggle(props) {
  const [isToggleOn, setIsToggleOn] = useState(true);

  // 방법 1. 함수 안에 함수로 정의
  function handleClick() {
    setIsToggleOn((isToggleOn) => !isToggleOn);
  }

  // 방법 2. arrow function을 사용하여 정의
  const handleClick = () => {
    setIsToggleOn((isToggleOn) => !isToggleOn);
  }

  return (
    <button onClick={handleClick}>
      {isToggleOn ? "켜짐" : "꺼짐"}
    </button>
  );
}
  • 이벤트 정의 방식
    1. 함수 안에 또다른 함수로 정의
    2. Arrow function을 사용
  • 이벤트 사용 방식 - this 사용 안 하고 onClick에 바로 적용 가능

🔎 Event Handler의 Arguments 전달하기


1) Arguments - Event Handler에 전달할 데이터
2) Parameter(매개변수)


클래스 컴포넌트

// 1번 방식
<button onClick={(event) => this.deleteItem(id, event)}>삭제하기</button>

// 2번 방식
<button onClick={this.deleteItem.bind(this, id)}>삭제하기</button>

두 방법 모두 첫 번째 매개변수 id, 두 번째 매개변수 event(리액트의 이벤트 객체)가 전달됨.

  1. arrow function - 명시적으로 이벤트를 두 번째로 전달
  2. bind - event가 자동으로 id 이후에 두 번째로 전달됨

함수 컴포넌트

function MyButton(props) {
  const handleDelete = (id, event) => {
    console.log(id, event.target);
  };

  return (
    <button onClick={(event) => handleDelete(1, event)}>
      삭제하기
    </button>
  );
}

결론

이벤트 핸들링은 프론트엔드 개발에서 핵심적인 개념입니다. JavaScript와 React의 이벤트 시스템은 유사하지만, 세부적인 동작 방식과 구현 패턴에서 차이가 있습니다. 특히 this 바인딩 문제는 클래스 컴포넌트에서 자주 발생하며, 이를 해결하기 위해 bind나 화살표 함수가 사용됩니다. 함수 컴포넌트에서는 이러한 문제를 상대적으로 간단하게 처리할 수 있습니다. 상황에 따라 적절한 이벤트 처리 방식을 선택함으로써 더 효율적이고 유지보수하기 쉬운 코드를 작성할 수 있기 때문에 적절히 선택하는 것이 중요합니다.

profile
개발새발

0개의 댓글