제어 컴포넌트와 비제어 컴포넌트는 React에서 주로 사용하는 개념으로, 이들 간의 차이점과 각자 언제 사용하는지 이해하는 것이 중요합니다. React에 의해서 값이 제어되는 컴포넌트를 제어 컴포넌트, React에 의해서 값이 제어되지 않는 컴포넌트를 비제어 컴포넌트라고 한다. 제어 컴포넌트는 React 애플리케이션에서 복잡한 UI 동작과 상태 관리를 쉽게 다룰 수 있도록 도와주며, 사용자가 입력한 데이터를 효과적으로 관리하고 검증할 수 있는 중요한 도구입니다.
상태 관리를 통한 UI 동기화가 필요한 경우: 사용자가 입력한 데이터가 React 컴포넌트의 상태(state)에 직접적으로 반영되고, 이 상태가 다시 UI에 영향을 미치는 경우 제어 컴포넌트를 사용합니다. 예를 들어, 입력 필드에 입력된 값이 특정 로직에 따라 실시간으로 유효성 검사를 받아야 한다면, 제어 컴포넌트가 적합합니다.
입력 데이터의 검증 및 처리: 사용자가 입력한 데이터를 즉시 검증하거나, 입력 내용에 따라 다른 동작을 유발해야 하는 경우에 제어 컴포넌트가 필요합니다. 예를 들어, 폼 데이터의 실시간 검증이나 특정 입력 값에 따라 버튼의 활성화/비활성화를 구현할 때 사용합니다.
폼의 초기값 설정 및 변경: 폼의 초기값을 프로그램적으로 설정하거나, 특정 이벤트에 의해 입력 필드의 값을 변경해야 할 때 제어 컴포넌트를 사용합니다.
외부 상태와 동기화: 컴포넌트 외부의 상태나 Redux, MobX 같은 상태 관리 라이브러리와 동기화가 필요할 때 제어 컴포넌트가 필요합니다. 이는 컴포넌트의 상태와 UI가 일관성 있게 유지되도록 합니다.
1. 일관된 상태 관리: 제어 컴포넌트는 모든 상태를 React 컴포넌트 내에서 관리하기 때문에, 상태 변화에 따라 UI가 일관되게 동작합니다. 이는 예측 가능성을 높여주며, 디버깅과 유지보수를 용이하게 합니다.
2. 데이터 검증 및 변환 용이: 사용자가 입력한 데이터를 실시간으로 검증하거나 변환할 수 있기 때문에, 데이터의 무결성을 보장하고, 원하는 형식으로 데이터를 유지할 수 있습니다.
3. React 철학에 부합: React의 주요 철학 중 하나는 "단방향 데이터 흐름"입니다. 제어 컴포넌트는 이 철학을 잘 반영하여, 데이터가 컴포넌트에서부터 UI로 흐르는 구조를 유지합니다.
4. 외부와의 데이터 동기화: 제어 컴포넌트를 통해, 입력 데이터와 컴포넌트 외부 상태를 쉽게 동기화할 수 있어, 중앙 집중화된 상태 관리가 가능합니다.
실제 프로젝트에서 제어 컴포넌트를 사용하는 몇 가지 예시는 다음과 같습니다:
로그인 폼: 사용자가 입력한 이메일과 비밀번호를 상태로 관리하고, 입력 내용에 따라 로그인 버튼을 활성화/비활성화하거나, 잘못된 입력에 대해 실시간으로 경고 메시지를 표시합니다.
검색 필터: 필터 옵션을 선택할 때마다 상태가 업데이트되고, 이 상태에 따라 검색 결과가 실시간으로 업데이트되는 검색 필터 UI를 구현할 때 제어 컴포넌트를 사용합니다.
실시간 채팅 애플리케이션: 채팅 입력 창에서 사용자가 입력한 메시지를 상태로 관리하고, 메시지가 입력되면 실시간으로 UI에 반영됩니다.
동적 폼 빌더: 사용자가 폼의 필드를 추가, 제거하거나 수정할 수 있는 동적 폼 빌더에서, 모든 필드의 상태를 관리하고, 상태에 따라 폼이 동적으로 렌더링되는 경우 제어 컴포넌트를 사용합니다.
우리는 form 이나 input 요소를 다룰 때 예시 코드
import React, { useState } from 'react';
function MyInput() {
const [inputValue, setInputValue] = useState(null);
const handleChange = (e) => {
setInputValue(e.target.value);
};
return <input onChange={(e) => handleChange(e)} value={inputValue} />;
}
위 코드는 input 의 값을 state로 관리하고 사용자가 값을 입력할 때마다 handleChange 를 통해 state 값을 업데이트 해주는 제어 컴포넌트이다. 제어 컴포넌트는 React, Real DOM, 사용자가 보는 화면을 동기화해줘야하는 번거로움이 있다.
import React, { useRef } from 'react';
function Test() {
return <MyInput />;
}
function MyInput() {
const inputNode = useRef(null);
return <input ref={inputNode} />;
}
export default MyInput;
위 코드는 input 의 값은 사용자만이 상호작용할 수 있고, 우리는 필요한 시점에 이벤트 핸들러를 통해 ref 에 저장된 엘리먼트의 값을 가져와 활용하는 비제어 컴포넌트이다. 비제어 컴포넌트는 state로 값을 관리하지 않기 때문에 값이 업데이트할 때마다 리렌더링이 되지 않기 때문에 성능상의 이점이 있다.
제어 컴포넌트는 입력 데이터를 상태로 관리하여 UI와의 일관성을 유지하고, 실시간 검증 및 변환이 필요한 경우에 사용합니다. 이를 통해 데이터의 예측 가능성과 무결성을 보장하며, 복잡한 UI 동작을 쉽게 다룰 수 있습니다. 실제로 로그인 폼, 검색 필터, 실시간 채팅 등에서 제어 컴포넌트를 사용해 입력 데이터를 효과적으로 관리하고 검증할 수 있습니다.
동적 폼 빌드 -> 필드 (필드가 더 적절한 단어): 각 필드의 상태를 제어 컴포넌트로 관리하여 사용자의 입력 및 조작에 따라 실시간으로 폼 구조와 데이터를 처리하는 것을 동적 폼 필드(빌더 -> 필드 )라고 칭함
리엑트 폼 필드 관리 모듈(react-hook-form) 이 따로 존재, 이를 가르키는 말
예시로는
설문조사 생성기: 설문 조사의 각 질문 필드를 추가/삭제하고, 각 질문에 대해 입력할 수 있는 동적 폼.
상품 옵션 관리: 상품의 여러 옵션(색상, 크기 등)을 추가하거나 제거할 수 있는 동적 UI.
유저 프로파일 생성기: 유저 프로파일을 구성하는 필드(이름, 나이, 이메일 등)를 유연하게 추가/수정할 수 있는 폼.
같이 폼 필드를 유연하게 또 바로 실시간으로 추가 수정할 수 있는 기능을 구현 할 때 제어 컴포넌트를 사용한다는 내용이였음