🎮 Controlled와 Uncontrolled - 리액트 폼 컴포넌트 이해하기
폼을 만들 때 상태를 컴포넌트가 관리하는 것을 Controlled 브라우저 DOM에 맡기는 것을 Uncontrolled 라고 한다.
두 방식의 기본 개념과 차이점에 대해 알아보자.
[기본 개념]
제어 컴포넌트(Controlled Component)
입력값의 단일 소스를 리액트 state로 두어 렌더링 시 input value가 채워지고 사용자가 타이핑 하면 onChange 함수로 state가 업데이트되어 리렌더링이 일어나는 방식이다.
예측이 가능하고 디버깅이 쉽다는 장점이 있다.
javascript
import { useState } from 'react';
export default function Controlled() {
const [name, setName] = useState('');
return (
<label>
이름
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
);
}
비제어 컴포넌트(Uncontrolled Component)
입력값의 실시간 상태는 DOM이 보유하고 초기값은 defaultValue/defaultChecked로 지정하는 방식을 의미한다. 필요한 순간에 ref.current.value 또는 FormData로 값을 읽어온다.
javascript
import { useRef } from 'react';
export default function Uncontrolled() {
const inputRef = useRef(null);
function handleSubmit(e) {
e.preventDefault();
const value = inputRef.current?.value ?? '';
alert('입력값: ' + value);
}
return (
<form onSubmit={handleSubmit}>
<label>
이름
<input
type="text"
defaultValue="BlueCool"
ref={inputRef}
/>
</label>
<button type="submit">등록</button>
</form>
);
}
파일 입력의 경우 브라우저 보안 정책상 value를 직접 제어할 수 없기 때문에 사실상 Uncontrolled여야 한다.
javascript
import { useRef } from 'react';
function FileInput() {
const ref = useRef(null);
return (
<div>
<input type="file" ref={ref} />
<button
onClick={() => {
if (ref.current) ref.current.value = '';
}}
>
초기화
</button>
</div>
);
}
제어 컴포넌트의 경우 값을 state로 관리하기 때문에 항상 최신값을 가지고 있어 입력 즉시 검증이 가능하다는 장점이 있다. 하지만 입력마다 리렌더링이 일어나 성능 비용이 커질 수 있다.
따라서 실시간 동기화, 검증, 제어가 필요한 경우 제어 컴포넌트를 파일 입력 혹은 타이핑 성능이 중요한 경우에는 비제어 컴포넌트를 사용하는것이 좋다.