ReactReact 기초 · 3기초

이벤트 처리 — 클릭, 입력, 폼 다루기

React이벤트onClickonChange폼처리

React 이벤트 시스템

React는 브라우저 이벤트를 SyntheticEvent로 감싸 크로스브라우저 일관성을 제공합니다.

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

// React (camelCase, 함수 참조)
<button onClick={handleClick}>클릭</button>

클릭 이벤트

import { MouseEvent } from "react";

function ButtonExample() {
    // 이벤트 객체 없이
    function handleSimpleClick() {
        console.log("클릭됨");
    }

    // 이벤트 객체 사용
    function handleClick(e: MouseEvent<HTMLButtonElement>) {
        console.log("클릭 위치:", e.clientX, e.clientY);
        e.preventDefault();  // 기본 동작 방지
    }

    // 인라인 + 추가 데이터
    return (
        <div>
            <button onClick={handleSimpleClick}>단순 클릭</button>
            <button onClick={handleClick}>이벤트 사용</button>
            {[1, 2, 3].map(id => (
                <button key={id} onClick={() => console.log(id)}>
                    항목 {id}
                </button>
            ))}
        </div>
    );
}

입력 이벤트

import { ChangeEvent, useState } from "react";

function InputExample() {
    const [value, setValue] = useState("");

    function handleChange(e: ChangeEvent<HTMLInputElement>) {
        setValue(e.target.value);
    }

    return (
        <div>
            <input
                type="text"
                value={value}          // 제어 컴포넌트
                onChange={handleChange}
                placeholder="입력하세요"
            />
            <p>입력값: {value}</p>
            <p>글자 수: {value.length}</p>
        </div>
    );
}

제어 vs 비제어 컴포넌트

// 제어 컴포넌트: React가 상태 관리 (권장)
<input value={value} onChange={e => setValue(e.target.value)} />

// 비제어 컴포넌트: DOM이 상태 관리
const inputRef = useRef<HTMLInputElement>(null);
<input ref={inputRef} defaultValue="초기값" />
// 값 읽기: inputRef.current?.value

폼 처리

import { FormEvent, useState } from "react";

interface LoginForm {
    email: string;
    password: string;
}

function LoginForm() {
    const [form, setForm] = useState<LoginForm>({ email: "", password: "" });
    const [error, setError] = useState<string | null>(null);
    const [isLoading, setIsLoading] = useState(false);

    function handleChange(e: ChangeEvent<HTMLInputElement>) {
        const { name, value } = e.target;
        setForm(prev => ({ ...prev, [name]: value }));
    }

    async function handleSubmit(e: FormEvent<HTMLFormElement>) {
        e.preventDefault();  // 페이지 새로고침 방지

        if (!form.email || !form.password) {
            setError("이메일과 비밀번호를 입력하세요.");
            return;
        }

        setIsLoading(true);
        setError(null);

        try {
            await login(form);
            alert("로그인 성공!");
        } catch (err) {
            setError("로그인에 실패했습니다.");
        } finally {
            setIsLoading(false);
        }
    }

    return (
        <form onSubmit={handleSubmit}>
            <input
                name="email"
                type="email"
                value={form.email}
                onChange={handleChange}
                placeholder="이메일"
            />
            <input
                name="password"
                type="password"
                value={form.password}
                onChange={handleChange}
                placeholder="비밀번호"
            />
            {error && <p className="error">{error}</p>}
            <button type="submit" disabled={isLoading}>
                {isLoading ? "로그인 중..." : "로그인"}
            </button>
        </form>
    );
}

키보드 이벤트

import { KeyboardEvent } from "react";

function SearchInput() {
    const [query, setQuery] = useState("");

    function handleKeyDown(e: KeyboardEvent<HTMLInputElement>) {
        if (e.key === "Enter") {
            performSearch(query);
        }
        if (e.key === "Escape") {
            setQuery("");
        }
    }

    return (
        <input
            value={query}
            onChange={e => setQuery(e.target.value)}
            onKeyDown={handleKeyDown}
            placeholder="Enter로 검색"
        />
    );
}

주요 이벤트 타입

이벤트타입요소
onClickMouseEvent<T>대부분
onChangeChangeEvent<T>input, select, textarea
onSubmitFormEvent<HTMLFormElement>form
onKeyDownKeyboardEvent<T>키보드 입력 가능 요소
onFocusFocusEvent<T>포커스 가능 요소
onBlurFocusEvent<T>포커스 가능 요소

정리

  • React 이벤트는 camelCase: onClick, onChange, onSubmit
  • e.preventDefault()로 기본 동작 방지
  • e.stopPropagation()으로 이벤트 버블링 중단
  • TypeScript에서 이벤트 타입을 명시하면 자동완성 지원
  • 폼은 onSubmit + e.preventDefault() 패턴 사용

다음 편에서는 useEffect — 컴포넌트 생명주기와 부수 효과를 처리하는 방법을 배웁니다.

궁금한 점이 있으신가요?

협업·의뢰는 아래로, 가벼운 소통은 인스타그램 @bluefox._.hi도 환영이에요.