[FE] 제어 vs 비제어 컴포넌트

seunghee.Rho·2025년 3월 10일

FE

목록 보기
5/26
post-thumbnail

Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components

개발도중 만난 Warning ..⚠️

해당 경고 메세지는 비제어 컴포넌트와 제어 컴포넌트를 혼용해서 사용할 때 발생하는 문제다.🔥
즉, 초기 value가 undefined였다가 나중에 값이 설정되면서 제어 컴포넌트로 변경되는 경우 발생한다.

먼저 제어 컴포넌트(Controlled Component)와 비제어 컴포넌트(Uncontrolled Component)가 뭔지 알아보았다.

1) 제어 컴포넌트

제어 컴포넌트는 React의 상태(state)를 통해 폼 요소의 값을 관리하는 방식이다.
즉, 입력값이 제어되며, 값이 변경될 때마다 React가 렌더링을 다시 수행한다.

특징

  • 입력 값이 state에 저장됨
  • onChange 이벤트를 통해 state를 업데이트해야 함
  • React에서 UI의 상태를 직접 제어
  • 폼 요소의 값을 추적하고 변경 사항을 감지할 수 있음

제어 컴포넌트가 적합한 경우

  • 폼 입력값을 검증해야 할 때(예: 실시간 유효성 검사)
  • 상태 기반 UI가 필요한 경우(예: 검색 기능, 자동 완성)
  • Redux, Zustand 등과 상태를 공유할 때

예시 코드

import { useState } from "react";

function ControlledInput() {
  const [text, setText] = useState("");

  return (
    <div>
      <input
        type="text"
        value={text}  // 상태 값으로 입력값을 제어
        onChange={(e) => setText(e.target.value)}  // 상태 업데이트
      />
      <p>입력된 값: {text}</p>
    </div>
  );
}

export default ControlledInput;

✔️ value 속성은 text 상태값을 반영한다.
✔️ onChange 핸들러를 통해 사용자가 입력할 때마다 state를 업데이트한다.
✔️ React가 폼 요소의 값을 직접 제어한다.

2) 비제어 컴포넌트

비제어 컴포넌트는 React의 state를 사용하지 않고, DOM 자체에서 값을 직접 관리하는 방식이다.
즉, useRef를 사용하여 폼 요소에 접근하고 값을 가져온다.

특징

  • useRef를 사용하여 DOM 요소에 접근
  • 입력 값이 React의 상태가 아니라 DOM에 저장됨
  • 값 변경 시 상태 업데이트 없이 직접 DOM에서 가져옴
  • React의 렌더링을 최소화하여 성능이 더 좋을 수 있음

비제어 컴포넌트가 적합한 경우

  • 입력값을 빠르게 가져와야 할 때(예: 파일 업로드, 포커스 제어)
  • 폼 요소를 초기화하거나 외부 라이브러리와 연동할 때
  • 성능 최적화가 필요할 때 (불필요한 리렌더링 방지)

예시 코드

import { useRef } from "react";

function UncontrolledInput() {
  const inputRef = useRef(null);

  const handleClick = () => {
    alert(`입력된 값: ${inputRef.current.value}`);
  };

  return (
    <div>
      <input type="text" ref={inputRef} />  {/* ref를 사용하여 DOM 직접 접근 */}
      <button onClick={handleClick}>값 확인</button>
    </div>
  );
}

export default UncontrolledInput;

✔️ ref를 사용하여 input 요소에 직접 접근한다
✔️ 버튼 클릭 시 ref.current.value를 가져와서 알림 창에 표시한다.
✔️ React의 상태를 사용하지 않으므로 불필요한 렌더링이 발생하지 않는다.

결론

제어 컴포넌트는 state를 통해 값을 관리하고, 비제어 컴포넌트는 ref를 사용해 DOM에 직접 접근한다.
제어 컴포넌트는 입력 값이 변경될 때마다 렌더링이 발생하지만, 비제어 컴포넌트는 렌더링 없이 값을 유지할 수 있다.

동적인 UI, 입력 값 검증, 실시간 반응이 필요한 경우에는 제어 컴포넌트가 적합하고,
성능 최적화가 필요하거나 초기값 설정이 중요한 경우에는 비제어 컴포넌트가 유리하다.

경고가 발생했던 이유는 value가 처음에는 undefined여서 비제어 컴포넌트로 간주되었지만, 이후 setValue로 값이 설정되면서 제어 컴포넌트로 변경되었기 때문이다.
➡️ 따라서, 제어 컴포넌트로 사용할 경우 초기값을 undefined가 아닌 빈 문자열 ""로 설정하면 경고를 방지할 수 있다.

👉🏻 결론적으로, 제어 컴포넌트와 비제어 컴포넌트는 각각의 장단점이 있으므로 상황에 맞게 선택하고, 혼용해서 사용하는 것은 피하는 것이 좋다.

profile
https://todaysdig.tistory.com/ 블로그 이전합니다...

0개의 댓글