2 분 소요

개요

React의 이벤트 처리는 HTML의 이벤트 처리와 유사하지만, 몇 가지 차이점이 있습니다. 이벤트 핸들러 이름은 카멜케이스를 사용하고, 함수를 직접 전달합니다.


기본 이벤트 처리

// HTML
// <button onclick="handleClick()">클릭</button>

// React JSX
function App() {
  const handleClick = () => {
    console.log("버튼 클릭!");
  };

  return (
    // 함수 참조를 전달 (함수 호출이 아님!)
    <button onClick={handleClick}>클릭</button>
  );
}

onClick={handleClick} ← 함수 참조 (매 클릭마다 호출)
onClick={handleClick()} ← ❌ 렌더링 즉시 호출됨 (주의!)


클릭 이벤트

import { useState } from "react";

function App() {
  const [count, setCount] = useState(0);
  const [message, setMessage] = useState("");

  const handleClick = () => {
    setCount(count + 1);
    setMessage(`${count + 1}번 클릭했습니다`);
  };

  // 인라인 함수 (간단한 경우)
  const handleReset = () => setCount(0);

  return (
    <div>
      <p>{message || "버튼을 클릭하세요"}</p>
      <button onClick={handleClick}>클릭 ({count})</button>
      <button onClick={handleReset}>초기화</button>
    </div>
  );
}


입력 이벤트 (가장 중요)

사용자 입력을 State와 동기화하는 제어 컴포넌트(Controlled Component) 패턴입니다.

import { useState } from "react";

function App() {
  const [name, setName] = useState("");

  // e = 이벤트 객체, e.target.value = 입력값
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setName(e.target.value);
  };

  return (
    <div>
      <input
        type="text"
        value={name}         // State와 연결 (제어 컴포넌트)
        onChange={handleChange}
        placeholder="이름 입력"
      />
      <p>입력: {name}</p>
    </div>
  );
}

value={name} + onChange = 입력 필드가 항상 State와 동기화
이를 제어 컴포넌트(Controlled Component)라고 합니다.


다양한 입력 타입

import { useState } from "react";

function App() {
  const [text, setText] = useState("");
  const [number, setNumber] = useState(0);
  const [checked, setChecked] = useState(false);
  const [selection, setSelection] = useState("apple");
  const [memo, setMemo] = useState("");

  return (
    <div>
      {/* 텍스트 입력 */}
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
      />

      {/* 숫자 입력 */}
      <input
        type="number"
        value={number}
        onChange={(e) => setNumber(Number(e.target.value))}
      />

      {/* 체크박스 */}
      <input
        type="checkbox"
        checked={checked}
        onChange={(e) => setChecked(e.target.checked)}  // .value가 아닌 .checked
      />

      {/* 셀렉트 */}
      <select
        value={selection}
        onChange={(e) => setSelection(e.target.value)}
      >
        <option value="apple">사과</option>
        <option value="banana">바나나</option>
      </select>

      {/* 텍스트 영역 */}
      <textarea
        value={memo}
        onChange={(e) => setMemo(e.target.value)}
      />
    </div>
  );
}


폼 제출

import { useState } from "react";

interface FormData {
  name: string;
  email: string;
}

function App() {
  const [form, setForm] = useState<FormData>({ name: "", email: "" });
  const [submitted, setSubmitted] = useState(false);

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;     // name 속성으로 필드 구분
    setForm({ ...form, [name]: value });
  };

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();   // 페이지 새로고침 방지 (필수!)
    console.log("제출:", form);
    setSubmitted(true);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        name="name"          // name 속성으로 handleChange에서 구분
        value={form.name}
        onChange={handleChange}
        placeholder="이름"
      />
      <input
        name="email"
        type="email"
        value={form.email}
        onChange={handleChange}
        placeholder="이메일"
      />
      <button type="submit">제출</button>
      {submitted && <p>제출 완료!</p>}
    </form>
  );
}


이벤트 객체

function App() {
  const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
    console.log(e.target);          // 이벤트 발생 요소
    console.log(e.currentTarget);   // 이벤트 핸들러가 달린 요소
    console.log(e.clientX, e.clientY); // 마우스 좌표
  };

  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === "Enter") {
      console.log("엔터 입력!");
    }
    if (e.key === "Escape") {
      console.log("ESC 입력!");
    }
  };

  return (
    <div>
      <button onClick={handleClick}>클릭</button>
      <input onKeyDown={handleKeyDown} placeholder="Enter/ESC 눌러보기" />
    </div>
  );
}


주요 이벤트 목록

이벤트 타입 설명
onClick MouseEvent 클릭
onChange ChangeEvent 입력값 변경
onSubmit FormEvent 폼 제출
onKeyDown / onKeyUp KeyboardEvent 키 입력
onFocus / onBlur FocusEvent 포커스 획득/잃음
onMouseEnter / onMouseLeave MouseEvent 마우스 진입/이탈
onScroll UIEvent 스크롤


이벤트 전파 중단

function Parent() {
  return (
    <div onClick={() => console.log("부모 클릭")}>
      <button
        onClick={(e) => {
          e.stopPropagation();   // 이벤트 버블링 중단
          console.log("자식 클릭만");
        }}
      >
        클릭
      </button>
    </div>
  );
}


관련 링크