처음 만난 리액트 문서


8.1 이벤트 처리하기

먼저 리액트에서 이벤트를 처리하는 방법을 알아보기 전에, DOM의 이벤트에 대해서 알아보도록 하겠습니다. 아래 코드는 DOM에서 클릭 이벤트를 처리하는 예시 코드입니다. 버튼이 눌리면 activate()라는 함수를 호출하도록 되어 있습니다. DOM에서는 클릭 이벤트를 처리할 함수를 onclick을 통해서 전달합니다.

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

그렇다면 리액트에서는 이벤트를 어떻게 처리할까요? 아래 코드는 위 코드와 동일한 기능을 하도록 만든 리액트 코드입니다. 자세히 보면 DOM의 이벤트와는 조금 다른 부분이 있습니다. 먼저 이벤트의 이름인 onclickonClick으로 Camel case로 쓰여 있습니다. Camel case에 대해서는 아래 노트를 참고하세요. 그리고 두 번째 다른 점은 DOM에서는 이벤트를 처리할 함수를 문자열로 전달했는데, 리액트에서는 함수를 그대로 전달한다는 점입니다.

<button onClick={activate}>
    Activate
</button>

이처럼 DOM에도 이벤트가 있고, 리액트에도 이벤트가 있지만 사용하는 방법이 조금은 다르다는 것을 기억하기 바랍니다. 그렇다면 이벤트는 어떻게 처리해야 할까요? 위에서 본 예시 코드처럼 어떤 이벤트가 발생했을 때 그 이벤트를 처리하는 함수가 있는데, 그것을 이벤트 핸들러(Event Handler) 라고 부릅니다. 다른 용어로는 이벤트가 발생하는 것을 계속 듣고 있는다는 의미에서 이벤트 리스너(Event Listener) 라고 부르기도 합니다. 그렇다면 이벤트 핸들러를 어떻게 추가해야 할까요? 아래 예제 코드를 보도록 하겠습니다.

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>
        );
    }
}

위 코드에는 Toggle이라는 클래스 컴포넌트가 나옵니다. 그리고 컴포넌트의 state에는 isToggleOn이라는 boolean변수가 하나 있습니다. 버튼을 클릭하면 이벤트 핸들러 함수인 handleClick()함수를 호출하도록 되어 있는데, 여기서 눈여겨 봐야 할 부분은 바로 handleClick()함수를 정의하는 부분과 this.handleClick = this.handleClick.bind(this); 부분입니다.

먼저 handleClick()함수의 정의 부분은 일반적인 함수를 정의하는 것과 동일하게 괄호와 중괄호를 사용해서 클래스의 함수로 정의하고 있습니다. 그리고 이렇게 정의된 함수를 constructor()에서 bind()를 이용하여 this.handleClick에 대입해줍니다.

JSX에서 this의 의미에 대해서 유의해야 하는데, bind를 하는 이유는 자바스크립트에서는 기본적으로 클래스 함수들이 바운드(Bound) 되지 않기 때문입니다. 그래서 bind를 하지 않으면 this.handleClick은 글로벌 스코프(global scope)에서 호출되는데, 글로벌 스코프에서 this.handleClickundefined이므로 사용할 수가 없습니다. 이것은 리액트에서만 해당되는 내용이 아니라 자바스크립트 함수의 작동원리의 일부분입니다. 그래서 일반적으로 함수의 이름 뒤에 괄호() 없이 사용하려면, 무조건 해당 함수를 bind 해줘야 합니다. bind에 대한 더 자세한 내용은 아래 링크를 참고하기 바랍니다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind

bind를 사용하는 방식이 번거롭게 느껴진다면, 아래 예시 코드처럼 클래스 필드 문법(Class fields syntax) 을 사용할 수 있습니다.

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

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

그리고 bind도 사용하지 않고 클래스 필드 문법(Class fields syntax)도 사용하지 않으려면, 아래와 같이 이벤트 핸들러를 넣는 곳에 arrow function을 사용하는 방법도 있습니다.

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

    render() {
        // 이렇게 하면 `this`가 바운드 됩니다.
        return (
            <button onClick={() => this.handleClick()}>
                클릭
            </button>
        );
    }
}

하지만 지금은 클래스 컴포넌트는 거의 사용하지 않기 때문에 위 내용은 참고로만 알고있기 바랍니다. 위에 나왔던 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>
    );
}

함수 컴포넌트 내부에서 이벤트 핸들러를 정의하는 방법은 위 코드처럼 함수안에 또 다른 함수로 정의하는 방법과 arrow function을 사용하여 정의하는 방법이 있습니다. 함수 컴포넌트에서는 this를 사용하지 않고, 위 코드처럼 onClick에 곧바로 handleClick을 넘기면 됩니다.

NOTE. Camel case
Camel case는 사막에 있는 낙타의 등의 모양을 보고 이름을 지은 것인데요, 낙타의 등을 보면 혹이 있어서 오르락 내리락 하는 것을 볼 수 있습니다. 이처럼 Camel case는 첫 글자는 소문자로 시작하되, 중간에 나오는 새로운 단어의 첫 글자를 대문자로 사용하여 글자의 크기가 변하는게 마치 낙타의 등과 같다고 해서 지어진 이름입니다. 위에서 나온 onClick도 첫 알파벳 o는 소문자로 쓰여 있고, 다음에 나오는 단어인 click의 첫 글자인 C는 대문자로 시작하는 Camel case입니다.

camelCase


마지막 업데이트: 2025년 08월 21일 09시 05분

이 문서의 저작권은 이인제(소플)에 있습니다. 무단 전재와 무단 복제를 금합니다.

On this page

  • 8.1 이벤트 처리하기