프로그래밍/ReactJS

React 폼 다루기: 비제어 컴포넌트의 이해와 활용

shimdh 2025. 10. 11. 00:23
728x90

React 애플리케이션에서 폼은 사용자와의 상호작용에 있어 핵심적인 요소입니다. 사용자로부터 데이터를 입력받고 이를 처리하거나 저장하는 과정은 인터랙티브한 웹 애플리케이션을 구축하는 데 필수적이죠. React에서 폼 입력을 처리하는 방식은 크게 '제어 컴포넌트'와 '비제어 컴포넌트'로 나눌 수 있습니다. 오늘 우리는 특히 '비제어 컴포넌트'에 대해 깊이 있게 탐구해보고자 합니다.

728x90

비제어 컴포넌트란 무엇인가요?

비제어 컴포넌트는 React의 useState와 같은 훅을 사용하여 입력 필드의 값을 제어하는 대신, 컴포넌트 자체적으로 내부 상태를 관리하는 방식입니다. 즉, React의 상태 관리 시스템에 의존하지 않고 DOM에 직접 접근하여 입력 필드의 값을 제어합니다. 이는 마치 전통적인 JavaScript에서 DOM 요소를 직접 다루는 방식과 유사하다고 할 수 있습니다.

주요 특징

비제어 컴포넌트의 핵심적인 특징들은 다음과 같습니다.

  • 직접 접근: DOM 요소와 직접적으로 상호작용합니다. useRef 훅을 사용하여 특정 DOM 요소에 대한 참조(reference)를 생성하고, 이 참조를 통해 해당 요소의 현재 값에 접근합니다.
  • 간소화된 코드: 모든 변경에 대해 일일이 이벤트 핸들러를 설정할 필요가 없어 코드를 간소화할 수 있습니다. 예를 들어, 입력 필드의 값이 변경될 때마다 React 상태를 업데이트하는 코드를 작성할 필요가 없습니다.
  • 간단한 폼에 적합: 각 입력 필드의 상태를 실시간으로 추적할 필요가 없는 간단한 폼에 가장 적합한 방식입니다. 복잡한 유효성 검사나 동적인 UI 업데이트가 필요 없는 경우, 비제어 컴포넌트가 더 효율적일 수 있습니다.

실용적인 예시: 비제어 컴포넌트로 간단한 폼 구축하기

이제 간단한 연락처 폼을 비제어 컴포넌트를 사용하여 구축하는 실제 예시를 살펴보겠습니다.

import React, { useRef } from 'react';

function ContactForm() {
  // 각 입력 필드에 대한 ref 생성
  const nameRef = useRef(null);
  const emailRef = useRef(null);

  const handleSubmit = (event) => {
    event.preventDefault(); // 기본 폼 제출 동작 방지

    // ref를 통해 값에 접근
    const name = nameRef.current.value;
    const email = emailRef.current.value;
    console.log('이름:', name);
    console.log('이메일:', email);
    // 선택적으로 제출 후 필드 비우기
    nameRef.current.value = '';
    emailRef.current.value = '';
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="name">이름:</label>
        <input type="text" id="name" ref={nameRef} />
      </div>
      <div>
        <label htmlFor="email">이메일:</label>
        <input type="email" id="email" ref={emailRef} />
      </div>
      <button type="submit">제출</button>
    </form>
  );
}

export default ContactForm;

예시 설명

  1. Ref 생성: useRef 훅을 사용하여 nameRefemailRef라는 두 개의 레퍼런스를 생성합니다. 이 레퍼런스들은 각각 이름 입력 필드와 이메일 입력 필드의 DOM 요소에 연결될 것입니다.
  2. 제출 처리 (handleSubmit 함수):
    • event.preventDefault(): 폼 제출 시 발생하는 기본 동작(페이지 새로고침 등)을 방지합니다. 이는 SPA(Single Page Application)에서 매우 중요합니다.
    • nameRef.current.valueemailRef.current.value: 각각의 ref.current는 해당 DOM 요소를 가리키며, .value를 통해 입력 필드의 현재 값을 가져올 수 있습니다.
    • console.log: 가져온 값을 콘솔에 출력하여 확인합니다. 실제 애플리케이션에서는 이 값들을 서버로 전송하거나 다른 로직에 활용할 것입니다.
    • 입력 필드 초기화: 선택적으로, 폼 제출 후 ref.current.value = ''를 사용하여 입력 필드의 값을 비울 수 있습니다.
  3. 입력 렌더링: <input> 요소에 ref={nameRef}와 같이 ref 속성을 사용하여 생성한 레퍼런스를 연결합니다. 이렇게 하면 React가 해당 DOM 요소와 레퍼런스를 연결시켜줍니다.

비제어 컴포넌트의 활용 시나리오

비제어 컴포넌트는 다음과 같은 특정 시나리오에서 특히 유용하게 사용될 수 있습니다.

  • DOM을 직접 조작하는 타사 라이브러리 통합: 예를 들어, 특정 날짜 선택기(Date Picker) 라이브러리가 DOM을 직접 조작하여 값을 설정하는 경우, 비제어 컴포넌트 방식이 더 자연스럽게 통합될 수 있습니다.
  • 상태 관리가 불필요한 간단한 폼: 각 입력 필드의 실시간 상태를 React 상태로 관리하는 것이 오히려 불필요한 복잡성을 초래할 수 있는 간단한 폼(예: 검색 바, 일회성 데이터 입력 폼)에 적합합니다.
  • 성능이 중요한 상황: 제어 컴포넌트는 입력 필드의 값이 변경될 때마다 React 상태를 업데이트하고, 이로 인해 컴포넌트가 재렌더링될 수 있습니다. 비제어 컴포넌트는 이러한 재렌더링을 피함으로써 특정 경우에 성능상 이점을 제공할 수 있습니다.

비제어 컴포넌트의 한계

비제어 컴포넌트는 코드의 반복을 줄이고 특정 시나리오에서 유용하지만, 제어 컴포넌트에 비해 몇 가지 한계점도 존재합니다.

  • 동적 유효성 검사의 어려움: 사용자 입력을 실시간으로 검증하고 피드백을 제공하는 것이 제어 컴포넌트에 비해 어렵습니다. 입력이 변경될 때마다 상태를 업데이트하지 않으므로, 유효성 검사 로직을 폼 제출 시점에 한 번에 처리해야 할 수 있습니다.
  • 애플리케이션 로직 기반 제약 적용의 어려움: 특정 입력 필드의 값이 다른 입력 필드의 UI나 유효성에 영향을 미치는 등, 애플리케이션 로직에 기반한 복잡한 제약을 적용하기가 까다로울 수 있습니다.

결론: 적절한 접근 방식 선택의 중요성

React에서 폼을 다루는 제어 컴포넌트와 비제어 컴포넌트 두 가지 접근 방식을 모두 이해하는 것은 개발자에게 큰 유연성을 제공합니다. 각 방식은 고유의 장점과 한계를 가지고 있으므로, 애플리케이션의 특정 요구 사항과 복잡성에 따라 가장 적합한 솔루션을 선택하는 것이 중요합니다. 간단하고 일회성인 입력이 필요한 경우 비제어 컴포넌트가 더 효율적일 수 있으며, 실시간 유효성 검사나 복잡한 상호작용이 필요한 경우에는 제어 컴포넌트가 더 나은 선택일 수 있습니다. 현명한 선택을 통해 더 견고하고 효율적인 React 애플리케이션을 구축하시길 바랍니다!

728x90