제어되지 않은 vs 제어된 React 컴포넌트
Source: Dev.to
React는 개발자에게 애플리케이션 내에서 컴포넌트를 관리하고 다루는 다양한 방법을 제공합니다. 두 가지 흔히 사용되는 접근 방식은 uncontrolled 컴포넌트와 controlled 컴포넌트입니다. 두 방식 모두 사용자 입력과 상호작용을 관리한다는 목적은 같지만, 구현 방식과 사용 사례에서는 큰 차이가 있습니다.
Uncontrolled Components
Uncontrolled 컴포넌트는 상태를 DOM이 보관하도록 합니다. React가 값을 직접 제어하지 않고, 필요할 때(예: 폼 제출 시) DOM에서 값을 읽어옵니다.
Advantages
- DOM‑driven: 폼 데이터가 DOM 자체에 의해 관리됩니다.
- Integration with non‑React code: 외부 라이브러리나 레거시 코드와 연동할 때, 진실된 데이터 소스가 DOM에 남아 있어 작업이 용이합니다.
- Simplified implementation: 상태 핸들러가 적게 필요하므로, 큰 폼을 만들 때 편리합니다.
- Potential performance benefit: React가 모든 입력 변화에 관여하지 않으므로, 재렌더링 오버헤드가 감소할 수 있습니다.
Disadvantages
- Limited control: 검증 규칙을 강제하거나 다른 React 기능(예: Context, PropTypes)과 동기화하기가 어렵습니다.
- Testing challenges: 상태가 DOM에 존재하기 때문에, 상호작용을 시뮬레이션하고 결과를 검증하는 것이 복잡해질 수 있습니다.
Example
import React, { useRef } from "react";
function UncontrolledForm() {
const inputRef = useRef(null);
function handleSubmit(event) {
event.preventDefault();
console.log("Submitted value:", inputRef.current.value);
}
return (
Name:
Submit
);
}
export default UncontrolledForm;
위 예시에서 입력값은 DOM(defaultValue)에 의해 관리됩니다. React는 폼이 제출될 때만 현재 값을 읽어옵니다.
Controlled Components
Controlled 컴포넌트는 상태를 React 내부에 보관합니다. 컴포넌트가 렌더링될 때마다 출력은 현재 상태를 반영하고, 사용자 상호작용은 이벤트 핸들러를 통해 상태를 업데이트합니다.
Advantages
- Full control: React가 검증을 강제하고, 다른 기능과 통합하며, 예측 가능한 동작을 보장할 수 있습니다.
- Improved testing: 상태가 명시적이므로, 변화를 시뮬레이션하고 결과를 검증하기가 쉽습니다.
- Centralized state management: 모든 폼 데이터가 React 상태에 존재하므로, 공유와 조작이 간편합니다.
- Clear event handling:
onChange(또는 유사) 핸들러가 UI와 상태를 동기화합니다.
Disadvantages
- Increased complexity: 각 입력마다 명시적인 상태 처리가 필요하므로, 큰 폼에서는 코드가 장황해질 수 있습니다.
- Potential performance overhead: 빈번한 상태 업데이트가 재렌더링을 유발해, 매우 크거나 인터랙티브한 폼에서는 성능에 영향을 줄 수 있습니다.
Example
import React, { useState } from "react";
function ControlledForm() {
const [name, setName] = useState("John Doe");
function handleChange(event) {
setName(event.target.value);
}
function handleSubmit(event) {
event.preventDefault();
console.log("Submitted value:", name);
}
return (
Name:
Submit
);
}
export default ControlledForm;
여기서는 입력의 value가 React 상태(name)에 바인딩됩니다. onChange 핸들러가 상태를 업데이트해 UI가 항상 현재 값을 반영하도록 합니다.