icon안동민 개발노트

제어 컴포넌트와 비제어 컴포넌트


 React에서 폼을 다루는 방식은 크게 두 가지로 나눌 수 있습니다.

 제어 컴포넌트(Controlled Components)

 비제어 컴포넌트(Uncontrolled Components)

 이 두 방식은 각각 고유한 특징과 사용 사례를 가지고 있습니다.

제어 컴포넌트

 제어 컴포넌트는 React에 의해 값이 완전히 제어되는 입력 폼 요소를 말합니다.

 특징

  1. 폼 데이터가 React 컴포넌트의 state에 의해 관리됩니다.
  2. 모든 state 변경은 연관된 핸들러 함수를 통해 이루어집니다.

 구현 방법

import React, { useState } from 'react';
 
function ControlledForm() {
  const [inputValue, setInputValue] = useState('');
 
  const handleChange = (event) => {
    setInputValue(event.target.value);
  };
 
  const handleSubmit = (event) => {
    event.preventDefault();
    console.log('Submitted value:', inputValue);
  };
 
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={inputValue}
        onChange={handleChange}
      />
      <button type="submit">Submit</button>
    </form>
  );
}

 이 예제에서 inputValue는 컴포넌트의 state로 관리되며, 사용자가 입력할 때마다 handleChange 함수를 통해 업데이트됩니다.

 장점

  1. 입력값에 대한 즉각적인 검증이 가능합니다.
  2. 조건에 따라 제출 버튼을 비활성화하는 등의 제어가 용이합니다.
  3. 폼 데이터의 형식을 강제할 수 있습니다.

 단점

  1. 각 입력 필드마다 state와 핸들러 함수가 필요하여 코드가 길어질 수 있습니다.
  2. 많은 입력 필드가 있는 경우 성능 문제가 발생할 수 있습니다.

비제어 컴포넌트

 비제어 컴포넌트는 폼 데이터가 DOM 자체에 의해 처리되는 방식입니다.

 특징

  1. React state를 사용하지 않고 DOM을 직접 조작합니다.
  2. ref를 사용하여 DOM 노드의 값을 가져옵니다.

 구현 방법

import React, { useRef } from 'react';
 
function UncontrolledForm() {
  const inputRef = useRef(null);
 
  const handleSubmit = (event) => {
    event.preventDefault();
    console.log('Submitted value:', inputRef.current.value);
  };
 
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        ref={inputRef}
        defaultValue="Default value"
      />
      <button type="submit">Submit</button>
    </form>
  );
}

 이 예제에서는 useRef를 사용하여 input 요소에 대한 참조를 만들고, 제출 시 그 값을 읽어옵니다.

 장점

  1. 구현이 간단합니다.
  2. 특정 상황(파일 입력 등)에서 유용할 수 있습니다.
  3. 기존의 non-React 코드와 통합하기 쉽습니다.

 단점

  1. 실시간으로 입력값을 검증하거나 조작하기 어렵습니다.
  2. 폼 데이터의 일관된 관리가 어려울 수 있습니다.

사용 가이드라인

  1. 제어 컴포넌트 사용 시기
  • 실시간 입력 검증이 필요한 경우
  • 입력값에 따라 다른 UI 요소를 조작해야 하는 경우
  • 제출 전 입력값 가공이 필요한 경우
  • 하나의 이벤트에서 여러 입력을 처리해야 하는 경우
  1. 비제어 컴포넌트 사용 시기
  • 간단한 폼에서 빠른 구현이 필요한 경우
  • 파일 입력 필드를 다룰 때
  • 기존의 non-React 코드와 통합해야 할 때
  • 대규모 폼에서 성능 최적화가 필요한 경우

혼합 사용 예제

 때로는 제어 컴포넌트와 비제어 컴포넌트를 혼합하여 사용하는 것이 유용할 수 있습니다.

import React, { useState, useRef } from 'react';
 
function MixedForm() {
  const [inputValue, setInputValue] = useState('');
  const fileInputRef = useRef(null);
 
  const handleInputChange = (event) => {
    setInputValue(event.target.value);
  };
 
  const handleSubmit = (event) => {
    event.preventDefault();
    console.log('Text input:', inputValue);
    console.log('File:', fileInputRef.current.files[0]);
  };
 
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={inputValue}
        onChange={handleInputChange}
      />
      <input
        type="file"
        ref={fileInputRef}
      />
      <button type="submit">Submit</button>
    </form>
  );
}

 이 예제에서 텍스트 입력은 제어 컴포넌트로, 파일 입력은 비제어 컴포넌트로 구현되었습니다.

 React에서 폼을 다룰 때 제어 컴포넌트와 비제어 컴포넌트 중 어떤 것을 선택할지는 상황에 따라 다릅니다. 제어 컴포넌트는 더 많은 제어와 즉각적인 검증을 제공하지만, 구현이 복잡할 수 있습니다. 반면 비제어 컴포넌트는 구현이 간단하지만, 실시간 데이터 접근과 조작이 제한적입니다.

 대부분의 경우 제어 컴포넌트를 사용하는 것이 React의 데이터 흐름 철학에 더 부합하며, 컴포넌트의 예측 가능성과 재사용성을 높일 수 있습니다. 그러나 파일 업로드와 같은 특정 상황이나, 성능 최적화가 필요한 대규모 폼에서는 비제어 컴포넌트가 더 적합할 수 있습니다.

 결국 두 방식의 장단점을 잘 이해하고, 프로젝트의 요구사항과 상황에 맞게 적절한 방식을 선택하는 것이 중요합니다. 때로는 두 방식을 혼합하여 사용하는 것도 좋은 해결책이 될 수 있습니다.