Home

React 리렌더링 시 Input 값 초기화 문제 Controlled vs Uncontrolled 컴포넌트 완벽 가이드

Published in react
November 17, 2025
3 min read
React 리렌더링 시 Input 값 초기화 문제 Controlled vs Uncontrolled 컴포넌트 완벽 가이드

안녕하세요, 여러분! 20년 넘게 React와 함께한 “코딩하는곰”입니다. 오늘은 React 개발자라면 한 번쯤 마주치는 고민, “컴포넌트가 리렌더링될 때 input 값이 초기화되는 문제”에 대해 깊이 있게 다루어보려고 합니다. 특히 Controlled와 Uncontrolled 컴포넌트의 차이를 중심으로 어떤 상황에서 어떤 접근법이 더 적합한지, 실제 프로젝트에서 겪었던 경험과 함께 상세히 설명드리겠습니다. 이 글을 통해 여러분의 React 폼 처리 기술을 한 단계 업그레이드하시길 바랍니다!

리렌더링과 Input 값 초기화 문제의 본질

React에서 컴포넌트가 리렌더링될 때 input 값이 사라지는 현상은 많은 개발자들을 당황하게 만듭니다. 이 문제의 근본적인 원인은 React의 상태 관리와 컴포넌트 생명주기에 있습니다.

React의 리렌더링 메커니즘

React는 상태(state)가 변경되거나 부모 컴포넌트에서 전달받는 props가 변경될 때 컴포넌트를 리렌더링합니다. 이 과정에서 가상 DOM(Virtual DOM)이 재생성되고, 실제 DOM과의 비교(diffing)를 통해 필요한 부분만 업데이트됩니다. 하지만 input 요소의 경우, 이 메커니즘이 예상과 다르게 동작할 때가 있습니다.

// 문제가 발생하는 일반적인 예시
function ProblematicForm() {
const [count, setCount] = useState(0);
const handleSubmit = (e) => {
e.preventDefault();
// 폼 제출 처리
};
return (
<div>
<button onClick={() => setCount(count + 1)}>
카운트 증가: {count}
</button>
<form onSubmit={handleSubmit}>
<input type="text" placeholder="입력해보세요" />
</form>
</div>
);
}

위 예제에서 버튼을 클릭할 때마다 컴포넌트가 리렌더링되면서 input에 입력한 값이 사라집니다. 이는 input이 uncontrolled 상태로 관리되고 있기 때문입니다.

리렌더링을 유발하는 주요 요인

  1. 상태 변경: useState, useReducer 훅을 통한 상태 업데이트
  2. Props 변경: 부모 컴포넌트로부터 전달받는 props의 값 변화
  3. 컨텍스트 변경: useContext 훅을 통해 구독 중인 컨텍스트 값 변경
  4. 부모 컴포넌트 리렌더링: 부모가 리렌더링되면 자식 컴포넌트도 함께 리렌더링 이러한 리렌더링 과정에서 input 요소의 값을 올바르게 유지하기 위해서는 Controlled와 Uncontrolled 컴포넌트의 개념을 정확히 이해하는 것이 중요합니다.

React 리렌더링 시 Input 값 초기화 문제 Controlled vs Uncontrolled 컴포넌트 완벽 가이드
React 리렌더링 시 Input 값 초기화 문제 Controlled vs Uncontrolled 컴포넌트 완벽 가이드


⚡ 개발 실력을 향상시키고 싶다면, (Vue.js) provide/inject API로 중첩 컴포넌트 데이터 공유하는 완벽 가이드를 참고해보세요.

Controlled 컴포넌트: React가 완전히 제어하는 입력 요소

Controlled 컴포넌트는 React의 상태(state)를 통해 input의 값을 완전히 제어하는 방식입니다. input의 value prop을 React 상태로 설정하고, onChange 이벤트를 통해 상태를 업데이트하는 패턴을 말합니다.

Controlled 컴포넌트의 기본 구현

import React, { useState } from 'react';
function ControlledForm() {
const [formData, setFormData] = useState({
username: '',
email: '',
password: ''
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('제출된 데이터:', formData);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="username">사용자명:</label>
<input
type="text"
id="username"
name="username"
value={formData.username}
onChange={handleChange}
/>
</div>
<div>
<label htmlFor="email">이메일:</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
</div>
<div>
<label htmlFor="password">비밀번호:</label>
<input
type="password"
id="password"
name="password"
value={formData.password}
onChange={handleChange}
/>
</div>
<button type="submit">제출</button>
</form>
);
}

Controlled 컴포넌트의 장점

  1. 즉각적인 유효성 검사: 사용자가 입력하는 즉시 유효성 검사를 수행할 수 있습니다.
  2. 조건부 제어: 입력값에 따라 다른 UI를 조건부로 렌더링할 수 있습니다.
  3. 통합된 상태 관리: 모든 입력값이 React 상태로 관리되어 일관된 데이터 흐름을 유지합니다.
  4. 외부에서의 제어: 부모 컴포넌트에서 자식 컴포넌트의 입력값을 제어할 수 있습니다.

Controlled 컴포넌트의 단점

  1. 성능 이슈: 매 입력마다 리렌더링이 발생하여 성능에 영향을 줄 수 있습니다.
  2. 복잡성 증가: 간단한 폼도 많은 상태와 이벤트 핸들러가 필요합니다.
  3. 메모리 사용량: 큰 폼의 경우 많은 상태를 관리해야 하므로 메모리 사용량이 증가합니다.

성능 최적화를 위한 Controlled 컴포넌트 패턴

import React, { useState, useCallback, useMemo } from 'react';
function OptimizedControlledForm() {
const [formData, setFormData] = useState({
username: '',
email: '',
password: ''
});
// useCallback을 사용한 메모이제이션
const handleChange = useCallback((e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
}, []);
// useMemo를 사용한 계산값 메모이제이션
const isFormValid = useMemo(() => {
return formData.username.length > 0 &&
formData.email.includes('@') &&
formData.password.length >= 8;
}, [formData]);
const handleSubmit = useCallback((e) => {
e.preventDefault();
if (isFormValid) {
console.log('제출된 데이터:', formData);
}
}, [formData, isFormValid]);
return (
<form onSubmit={handleSubmit}>
{/* 입력 필드들 */}
</form>
);
}

React 리렌더링 시 Input 값 초기화 문제 Controlled vs Uncontrolled 컴포넌트 완벽 가이드
React 리렌더링 시 Input 값 초기화 문제 Controlled vs Uncontrolled 컴포넌트 완벽 가이드


로또 번호를 QR코드로 빠르게 확인하고 싶다면, AI 기반 로또 번호 추천 앱 지니로또AI를 다운로드해보세요.

Uncontrolled 컴포넌트: DOM에 직접 접근하는 방식

Uncontrolled 컴포넌트는 React 상태 대신 DOM 자체에서 input 값을 관리하는 방식입니다. useRef 훅을 사용하여 DOM 요소에 직접 접근하고, 필요한 시점에 값을 읽어옵니다.

Uncontrolled 컴포넌트의 기본 구현

import React, { useRef } from 'react';
function UncontrolledForm() {
const usernameRef = useRef(null);
const emailRef = useRef(null);
const passwordRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
const formData = {
username: usernameRef.current.value,
email: emailRef.current.value,
password: passwordRef.current.value
};
console.log('제출된 데이터:', formData);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="username">사용자명:</label>
<input
type="text"
id="username"
ref={usernameRef}
defaultValue="" // 초기값 설정
/>
</div>
<div>
<label htmlFor="email">이메일:</label>
<input
type="email"
id="email"
ref={emailRef}
defaultValue=""
/>
</div>
<div>
<label htmlFor="password">비밀번호:</label>
<input
type="password"
id="password"
ref={passwordRef}
defaultValue=""
/>
</div>
<button type="submit">제출</button>
</form>
);
}

Uncontrolled 컴포넌트의 장점

  1. 성능 효율성: 입력 시 리렌더링이 발생하지 않아 성능이 더 좋습니다.
  2. 간단한 구현: 상태 관리가 필요 없어 코드가 간결해집니다.
  3. 네이티브 동작: React의 제어를 받지 않아 브라우저의 기본 동작에 가깝습니다.
  4. 파일 입력: file type input은 항상 uncontrolled로 사용해야 합니다.

Uncontrolled 컴포넌트의 단점

  1. 실시간 유효성 검사 어려움: 입력 중에 유효성 검사를 수행할 수 없습니다.
  2. 조건부 렌더링 제한: 입력값에 따른 조건부 UI 렌더링이 어렵습니다.
  3. 외부 제어 불가: 부모 컴포넌트에서 값을 제어할 수 없습니다.
  4. 테스트 어려움: DOM에 직접 의존하여 테스트가 더 복잡해집니다.

하이브리드 접근법: 필요 시점에만 값 읽기

import React, { useRef, useState } from 'react';
function HybridForm() {
const emailRef = useRef(null);
const [emailError, setEmailError] = useState('');
const validateEmail = () => {
const email = emailRef.current.value;
if (!email.includes('@')) {
setEmailError('유효한 이메일 주소를 입력해주세요');
} else {
setEmailError('');
}
};
const handleSubmit = (e) => {
e.preventDefault();
validateEmail();
if (!emailError) {
const formData = {
email: emailRef.current.value
};
console.log('제출된 데이터:', formData);
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="email">이메일:</label>
<input
type="email"
id="email"
ref={emailRef}
onBlur={validateEmail} // 포커스를 잃을 때만 검증
defaultValue=""
/>
{emailError && <span style={{color: 'red'}}>{emailError}</span>}
</div>
<button type="submit">제출</button>
</form>
);
}

실제 프로젝트에서의 선택 가이드라인

Controlled 컴포넌트를 선택해야 할 때:

  • 실시간 유효성 검사가 필요한 경우
  • 입력값에 따라 다른 UI를 보여줘야 하는 경우
  • 여러 입력값 간의 복잡한 상호작용이 필요한 경우
  • 외부에서 입력값을 제어해야 하는 경우 Uncontrolled 컴포넌트를 선택해야 할 때:
  • 성능이 중요한 대규모 폼인 경우
  • 간단한 폼으로 실시간 검사가 필요없는 경우
  • 파일 업로드와 같은 특수한 입력의 경우
  • 기존 비 React 코드와의 통합이 필요한 경우

React 리렌더링 시 Input 값 초기화 문제 Controlled vs Uncontrolled 컴포넌트 완벽 가이드
React 리렌더링 시 Input 값 초기화 문제 Controlled vs Uncontrolled 컴포넌트 완벽 가이드


로또 번호를 QR코드로 빠르게 확인하고 싶다면, AI 기반 로또 번호 추천 앱 지니로또AI를 다운로드해보세요.

지금까지 React에서 Controlled와 Uncontrolled 컴포넌트의 차이와 각각의 장단점, 사용 시나리오에 대해 자세히 알아보았습니다. 두 접근법 모두 각자의 장점이 있으며, 상황에 맞게 적절히 선택하는 것이 중요합니다. 개인적인 경험으로는 대부분의 경우 Controlled 컴포넌트를 사용하는 것이 React의 데이터 흐름과 잘 맞으며 유지보수성이 뛰어납니다. 하지만 성능이 중요한 대규모 애플리케이션에서는 Uncontrolled 컴포넌트를 적절히 활용하는 것이 좋습니다. 여러분의 프로젝트 요구사항, 성능 요구치, 개발 팀의 선호도에 따라 최적의 접근법을 선택하시길 바랍니다. React 개발자로서 이 두 패턴을 자유자재로 활용할 수 있다면 더 견고하고 효율적인 애플리케이션을 개발할 수 있을 것입니다. 다음 포스팅에서는 이어서 React 폼 라이브러리 비교와 실제 프로젝트 적용 사례에 대해 더 깊이 있게 다루어보겠습니다. 질문이 있으시면 언제든지 댓글로 남겨주세요! 함께 성장하는 React 개발자가 되는 그날까지, 코딩하는곰이 함께하겠습니다!

👍 믿을 수 있는 건강기능식품 트렌드를 알고 싶다면, 두뇌엔 포스파티딜세린&징코를 참고해보세요.









최상의 건강을 위한 영양가득한 식품과 정보! life-plus.co.kr 바로가기
최상의 건강을 위한 영양가득한 식품과 정보! life-plus.co.kr 바로가기



다채로운 문화축제와 공연 소식을 공유하는 블로그! culturestage.co.kr 바로가기
다채로운 문화축제와 공연 소식을 공유하는 블로그! culturestage.co.kr 바로가기



비트코인 세계로의 첫걸음! 지금 가입하고 거래 수수료 할인 혜택 받으세요! bitget.com 바로가기
비트코인 세계로의 첫걸음! 지금 가입하고 거래 수수료 할인 혜택 받으세요! bitget.com 바로가기




Tags

#developer#coding#react

Share

Previous Article
(MySQL/MariaDB) JOIN 문법 완전 정리 ① INNER, LEFT 조인의 모든 것

Table Of Contents

1
리렌더링과 Input 값 초기화 문제의 본질
2
Controlled 컴포넌트: React가 완전히 제어하는 입력 요소
3
Uncontrolled 컴포넌트: DOM에 직접 접근하는 방식

Related Posts

React 18의 주요 변화 완벽 가이드 자동 배치, 트랜지션, 동시성 기능까지
December 14, 2025
3 min