<input>
브라우저 내장 컴포넌트 를 사용하면 여러 종류의 form input 을 렌더링 할 수 있습니다.
<input />
레퍼런스
<input>
input 을 표시하려면, <input>
브라우저 내장 컴포넌트 를 렌더링 하세요.
<input name="myInput" />
Props
<input>
은 일반적인 엘리먼트 props 를 지원합니다.
formAction
: A string or function. Overrides the parent <form action>
for type="submit"
and type="image"
. When a URL is passed to action
the form will behave like a standard HTML form. When a function is passed to formAction
the function will handle the form submission. See <form action>
.
You can make an input controlled by passing one of these props:
checked
: 불리언 타입. 체크박스 input 또는 라디오 버튼에서 선택 여부를 제어합니다.value
: 문자열 타입. 텍스트 input의 경우 텍스트를 제어합니다. (라디오 버튼의 경우 폼 데이터를 지정합니다.)
둘 중 하나를 전달할 때는 반드시 전달된 값을 업데이트하는 onChange
핸들러도 함께 전달해야 합니다.
다음의 <input>
props 들은 제어되지 않는 input들에만 적용됩니다.
defaultChecked
: 불리언 타입.type="checkbox"
와type="radio"
input에 대한 초기값 을 지정합니다.defaultValue
: 문자열 타입. 텍스트 input에 대한 초기값 을 지정합니다.
다음의 <input>
props 들은 제어되지 않는 input과 제어되는 input 모두에 적용됩니다.
accept
: 문자열 타입.type="file"
input에서 허용할 파일 형식을 지정합니다.alt
: 문자열 타입.type="image"
input에서 대체 이미지 텍스트를 지정합니다.capture
: 문자열 타입.type="file"
input으로 캡처한 미디어(마이크, 비디오 또는 카메라)를 지정합니다.autoComplete
: 문자열 타입. 자동 완성 동작들 중 가능한 하나를 지정합니다.autoFocus
: 불리언 타입.true
일 경우 React는 마운트 시 엘리먼트에 포커스를 맞춥니다.dirname
: 문자열 타입. 엘리먼트 방향성에 대한 폼 필드 이름을 지정합니다.disabled
: 불리언 타입.true
일 경우, input은 상호작용이 불가능해지며 흐릿하게 보입니다.children
:<input>
은 자식을 받지 않습니다.form
: 문자열 타입. input이 속하는<form>
의id
를 지정합니다. 생략 시 가장 가까운 부모 폼으로 설정됩니다.formAction
: 문자열 타입.type="submit"
과type="image"
의 부모<form action>
을 덮어씁니다.formEnctype
: 문자열 타입.type="submit"
과type="image"
의 부모<form enctype>
을 덮어씁니다.formMethod
: 문자열 타입.type="submit"
과type="image"
의 부모<form method>
를 덮어씁니다.formNoValidate
: 문자열 타입.type="submit"
과type="image"
의 부모<form noValidate>
를 덮어씁니다.formTarget
: 문자열 타입.<form target>
fortype="submit"
과type="image"
의 부모<form target>
을 덮어씁니다.height
: 문자열 타입.type="image"
의 이미지 높이를 지정합니다.list
: 문자열 타입.<datalist>
의id
를 자동 완성 옵션들로 지정합니다.max
: 숫자 타입. 숫자 와 날짜 input들의 최댓값을 지정합니다.maxLength
: 숫자 타입. 텍스트와 다른 input들의 최대 길이를 지정합니다.min
: 숫자 타입. 숫자 와 날짜 input들의 최솟값을 지정합니다.minLength
: 숫자 타입. 텍스트와 다른 input들의 최소 길이를 지정합니다.multiple
: 불리언 타입.type="file"
과type="email"
에 대해 여러 값을 허용할지 여부를 지정합니다.name
: 문자열 타입. 폼과 제출 되는 input의 이름을 지정합니다.onChange
:이벤트
핸들러 함수. 제어되는 input 필수 요소로 가령 사용자가 키보드를 누를 때마다 실행되는 방식으로 input 값을 변경하는 즉시 실행되며 브라우저input
이벤트처럼 동작합니다.onChangeCapture
: 캡처 단계에서 실행되는onChange
onInput
:이벤트
핸들러 함수. 사용자가 값을 변경하는 즉시 실행됩니다. 지금까지의 용법에 비춰봤을 때 React에서는 유사하게 동작하는onChange
를 사용하는 것이 관습적입니다.onInputCapture
: 캡처 단계에서 실행되는onInput
onInvalid
:이벤트
핸들러 함수. 폼 제출 시 input이 유효하지 않을 경우 실행되며invalid
내장 이벤트와 달리 ReactonInvalid
이벤트는 버블링됩니다.onInvalidCapture
: 캡처 단계에서 실행되는onInvalid
onSelect
:이벤트
핸들러 함수.<input>
내부의 선택 사항이 변경된 후 실행됩니다. React는onSelect
이벤트를 확장하여 선택 사항이 비거나 편집 시 선택 사항에 영향을 끼치게 될 때도 실행됩니다.onSelectCapture
: 캡처 단계에서 실행되는onSelect
pattern
: 문자열 타입.value
가 일치해야 하는 패턴을 지정합니다.placeholder
: 문자열 타입. input 값이 비었을 때 흐린 색으로 표시됩니다.readOnly
: 불리언 타입.true
일 경우 사용자가 input을 편집할 수 없습니다.required
: 불리언 타입.true
일 경우 폼이 제출할 값을 반드시 제공해야 합니다.size
: 숫자 타입. 너비를 설정하는 것과 비슷하지만 단위는 제어에 따라 다릅니다.src
: 문자열 타입.type="image"
input의 이미지 소스를 지정합니다.step
: 양수 또는'any'
문자열. 유효한 값 사이의 간격을 지정합니다.type
: 문자열 타입. input types 중의 하나width
: 문자열 타입.type="image"
input의 이미지 너비를 지정합니다.
경고
- 체크박스에는
value
(또는defaultValue
)가 아닌checked
(또는defaultChecked
)가 필요합니다. - 텍스트 input 영역은 문자열
value
prop을 받을 경우 제어되는 것으로 취급됩니다. - 체크박스 또는 라디오 버튼이 불리언
checked
prop을 받을 경우 제어되는 것으로 취급됩니다. - input은 제어되면서 동시에 비제어될 수 없습니다.
- input은 생명주기 동안 제어 또는 비제어 상태를 오갈 수 없습니다.
- 제어되는 input엔 모두 백업 값을 동기적으로 업데이트하는
onChange
이벤트 핸들러가 필요합니다.
사용법
다양한 유형의 input 표시
input을 표시하기 위해 <input>
컴포넌트를 렌더링 하세요. 기본적으로 텍스트 input이 됩니다. 체크박스에는 type="checkbox"
를, 라디오 버튼에는 type="radio"
전달하거나 다른 input 타입들 중의 하나를 전달할 수 있습니다.
export default function MyForm() { return ( <> <label> Text input: <input name="myInput" /> </label> <hr /> <label> Checkbox: <input type="checkbox" name="myCheckbox" /> </label> <hr /> <p> Radio buttons: <label> <input type="radio" name="myRadio" value="option1" /> Option 1 </label> <label> <input type="radio" name="myRadio" value="option2" /> Option 2 </label> <label> <input type="radio" name="myRadio" value="option3" /> Option 3 </label> </p> </> ); }
input에 라벨 제공하기
일반적으로 모든 <input>
은 <label>
태그 안에 두게 되는데 이렇게 하면 해당 라벨이 해당 input과 연관됨을 브라우저가 알 수 있습니다. 사용자가 라벨을 클릭하면 브라우저는 input에 자동적으로 포커스를 맞춥니다. 스크린 리더는 사용자가 연관된 input에 포커스를 맞출 때 라벨 캡션을 읽게 되므로 이 방식은 접근성을 위해서도 필수입니다.
<label>
안에 <input>
을 감쌀 수 없다면, <input id>
와 <label htmlFor>
에 동일한 ID를 전달해서 연관성을 부여하세요. 한 컴포넌트의 여러 인스턴스 간 충돌을 피하려면 useId
로 그러한 ID를 생성하세요.
import { useId } from 'react'; export default function Form() { const ageInputId = useId(); return ( <> <label> Your first name: <input name="firstName" /> </label> <hr /> <label htmlFor={ageInputId}>Your age:</label> <input id={ageInputId} name="age" type="number" /> </> ); }
input에 초깃값 제공하기
input의 초깃값은 선택적으로 지정할 수 있습니다. 텍스트 input을 위한 defaultValue
문자열로 전달하세요. 대신 체크박스와 라디오 버튼은 defaultChecked
불리언으로 초깃값을 지정해야 합니다.
export default function MyForm() { return ( <> <label> Text input: <input name="myInput" defaultValue="Some initial value" /> </label> <hr /> <label> Checkbox: <input type="checkbox" name="myCheckbox" defaultChecked={true} /> </label> <hr /> <p> Radio buttons: <label> <input type="radio" name="myRadio" value="option1" /> Option 1 </label> <label> <input type="radio" name="myRadio" value="option2" defaultChecked={true} /> Option 2 </label> <label> <input type="radio" name="myRadio" value="option3" /> Option 3 </label> </p> </> ); }
폼 제출 시 input 값 읽기
inputs과 <button type="submit">
바깥을 <form>
으로 감싸면 버튼을 클릭했을 때 <form onSubmit>
이벤트 핸들러가 호출됩니다. 기본적으로 브라우저는 현재 URL에 폼 데이터를 전송한 후 페이지를 새로고침하며 이러한 동작은 e.preventDefault()
를 호출하여 덮어쓸 수 있습니다. 폼 데이터는 new FormData(e.target)
로 읽으세요.
export default function MyForm() { function handleSubmit(e) { // 브라우저가 페이지를 다시 로드하지 못하도록 방지합니다. e.preventDefault(); // 폼 데이터를 읽습니다. const form = e.target; const formData = new FormData(form); // formData를 직접 fetch body로 전달할 수 있습니다. fetch('/some-api', { method: form.method, body: formData }); // 또는 순수 object로 작업할 수 있습니다. const formJson = Object.fromEntries(formData.entries()); console.log(formJson); } return ( <form method="post" onSubmit={handleSubmit}> <label> Text input: <input name="myInput" defaultValue="Some initial value" /> </label> <hr /> <label> Checkbox: <input type="checkbox" name="myCheckbox" defaultChecked={true} /> </label> <hr /> <p> Radio buttons: <label><input type="radio" name="myRadio" value="option1" /> Option 1</label> <label><input type="radio" name="myRadio" value="option2" defaultChecked={true} /> Option 2</label> <label><input type="radio" name="myRadio" value="option3" /> Option 3</label> </p> <hr /> <button type="reset">Reset form</button> <button type="submit">Submit form</button> </form> ); }
state 변수로 input 제어하기
<input />
과 같은 input은 제어되지 않습니다. <input defaultValue="Initial text" />
와 같은 초깃값을 전달한대도 JSX는 당장의 값을 제어하지 않고 초깃값만을 지정합니다.
제어되는 input을 렌더링하려면, value
(또는 체크박스와 라디오에는 checked
) prop 을 전달하세요. React는 전달한 value
를 항상 갖도록 input에 강제합니다. 일반적으로 state 변수를 선언하여 할 수 있습니다.
function Form() {
const [firstName, setFirstName] = useState(''); // state 변수를 선언합니다.
// ...
return (
<input
value={firstName} // 입력 값이 state 변수와 일치하도록 강제합니다.
onChange={e => setFirstName(e.target.value)} // input을 편집할 때마다 state 변수를 업데이트합니다.
/>
);
}
예를 들어 수정할 때마다 UI를 리렌더링 하는 등 state가 필요한 경우 제어된 input이 적합합니다.
function Form() {
const [firstName, setFirstName] = useState('');
return (
<>
<label>
First name:
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</label>
{firstName !== '' && <p>Your name is {firstName}.</p>}
...
또한 버튼을 클릭하는 등의 input state를 조정하는 여러 가지 방법을 제공하려는 경우에도 유용합니다.
function Form() {
// ...
const [age, setAge] = useState('');
const ageAsNumber = Number(age);
return (
<>
<label>
Age:
<input
value={age}
onChange={e => setAge(e.target.value)}
type="number"
/>
<button onClick={() => setAge(ageAsNumber + 10)}>
Add 10 years
</button>
제어되는 컴포넌트에 전달되는 value
는 undefined
나 null
이 되어서는 안됩니다. 아래의 firstName
필드처럼 초깃값을 비워두어야 하는 경우 state 변수를 빈 문자열(''
)로 초기화 하세요.
import { useState } from 'react'; export default function Form() { const [firstName, setFirstName] = useState(''); const [age, setAge] = useState('20'); const ageAsNumber = Number(age); return ( <> <label> First name: <input value={firstName} onChange={e => setFirstName(e.target.value)} /> </label> <label> Age: <input value={age} onChange={e => setAge(e.target.value)} type="number" /> <button onClick={() => setAge(ageAsNumber + 10)}> Add 10 years </button> </label> {firstName !== '' && <p>Your name is {firstName}.</p> } {ageAsNumber > 0 && <p>Your age is {ageAsNumber}.</p> } </> ); }
키보드를 누를 때마다 리렌더링 최적화하기
제어된 input을 사용할 때는 키보드를 누를 때마다 state를 설정합니다. state를 포함하는 컴포넌트가 큰 트리를 리렌더링할 경우 속도가 느려질 수 있습니다. 리렌더링 성능을 최적화할 수 있는 몇 가지 방법이 있습니다.
예를 들어, 키보드를 누를 때마다 모든 페이지 내용을 리렌더링하는 폼으로 시작한다고 가정해보세요.
function App() {
const [firstName, setFirstName] = useState('');
return (
<>
<form>
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</form>
<PageContent />
</>
);
}
<PageContent />
는 input state에 의존하지 않으므로 input state를 자체 컴포넌트로 이동할 수 있습니다.
function App() {
return (
<>
<SignupForm />
<PageContent />
</>
);
}
function SignupForm() {
const [firstName, setFirstName] = useState('');
return (
<form>
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</form>
);
}
이렇게 하면 키보드를 누를 때마다 SignupForm
만 리렌더링하기 때문에 성능이 크게 향상됩니다.
PageContent
가 검색 input 값에 의존하는 경우처럼 리렌더링을 피할 방법이 없는 경우 useDeferredValue
를 사용하면 많은 리렌더링 중에도 제어된 input이 응답하도록 할 수 있습니다.
문제해결
텍스트 input에 타이핑을 해도 업데이트되지 않습니다
onChange
없이 value
만 전달하여 input을 렌더링하면 콘솔에 에러가 나타납니다.
// 🔴 버그: 제어되는 input에 onChange 핸들러가 없습니다.
<input value={something} />
onChange
핸들러 없이 value
prop만 전달했습니다. 이렇게 하면 읽기 전용 필드를 렌더링하게 됩니다. 필드가 변경 가능해야 하는 경우 defaultValue
를 사용하고 그렇지 않은 경우 onChange
또는 readOnly
를 설정하세요.에러 메시지가 제안하듯 초깃값만 지정하려면 defaultVallue
를 대신 전달하세요.
// ✅ 좋은 예: 제어되지 않는 input에 초깃값 전달
<input defaultValue={something} />
input을 state 변수로 제어하려면 onChange
핸들러를 지정하세요.
// ✅ 좋은 예: 제어되는 input에 onChange 전달
<input value={something} onChange={e => setSomething(e.target.value)} />
값이 의도적으로 읽기 전용이라면 에러를 막기 위해 readOnly
prop을 추가하세요.
// ✅ 좋은 예: 제어되는 읽기 전용 input에 onChange 생략
<input value={something} readOnly={true} />
체크박스를 클릭해도 업데이트되지 않습니다
onChange
없이 checked
만 전달하여 체크박스를 렌더링하면 콘솔에 에러가 나타납니다.
// 🔴 버그: 제어되는 체크박스에 onChange 핸들러가 없습니다.
<input type="checkbox" checked={something} />
onChange
핸들러 없이 checked
prop을 전달했습니다. 이렇게 하면 읽기 전용 필드를 렌더링하게 됩니다. 필드가 변경 가능해야 하는 경우 defaultChecked
를 사용하고 그렇지 않은 경우 onChange
또는 readOnly
를 설정하세요.에러 메시지가 제안하듯 초깃값만 지정하려면 defaultChecked
를 대신 전달하세요.
// ✅ 좋은 예: 제어되지 않는 체크박스에 초깃값 전달
<input type="checkbox" defaultChecked={something} />
체크박스를 state 변수로 제어하려면 onChange
핸들러를 지정하세요.
// ✅ 좋은 예: 제어되는 체크박스에 onChange 전달
<input type="checkbox" checked={something} onChange={e => setSomething(e.target.checked)} />
체크박스가 의도적으로 읽기 전용이라면 에러를 막기 위해 readOnly
prop을 추가하세요.
// ✅ 좋은 예: 제어되는 읽기 전용 input에 onChange 생략
<input type="checkbox" checked={something} readOnly={true} />
키보드를 누를 때마다 입력 커서가 input의 처음으로 돌아갑니다
input을 제어할 경우 onChange
안에서 state 변수를 DOM에서 받아온 input 값으로 업데이트해야 합니다.
state 변수는 e.target.value
(혹은 체크박스에서는 e.target.checked
) 외의 값으로 업데이트할 수 없습니다.
function handleChange(e) {
// 🔴 버그: input을 e.target.value 외의 값으로 업데이트합니다.
setFirstName(e.target.value.toUpperCase());
}
비동기로 업데이트할 수도 없습니다.
function handleChange(e) {
// 🔴 버그: input을 비동기로 업데이트합니다.
setTimeout(() => {
setFirstName(e.target.value);
}, 100);
}
코드를 고치려면 e.target.value
로 동기 업데이트하세요.
function handleChange(e) {
// ✅ 제어되는 input을 e.target.value로 동기 업데이트합니다.
setFirstName(e.target.value);
}
이 방법으로 문제가 해결되지 않을 경우 키보드를 누를 때마다 input이 DOM에서 제거된 후 다시 추가되고 있을 가능성이 있습니다. 실수로 리렌더링마다 state를 재설정하고 있다면 나타날 수 있는 현상입니다. 가령 input이나 input의 부모 중 하나가 매번 다른 key
어트리뷰트를 받거나 컴포넌트 함수 정의를 중첩시키는 경우(이는 지원되지 않으며 ‘내부’ 컴포넌트가 항상 다른 트리로 간주되도록 합니다)에 해당 문제가 발생할 수 있습니다.
다음과 같은 에러가 납니다. “A component is changing an uncontrolled input to be controlled(컴포넌트가 제어되지 않는 input을 제어 상태로 변경합니다)”
컴포넌트에 value
를 제공할 경우 반드시 생명주기 내내 문자열 타입으로 남아야 합니다.
React는 컴포넌트를 비제어할 것인지 제어할 것인지 의도를 알 수 없기 때문에 처음엔 value={undefined}
를 전달했다가 나중에 다시 value="some string"
을 전달할 수는 없습니다. 제어되는 컴포넌트는 항상 null
이나 undefined
가 아닌 문자열 value
를 받아야 합니다.
value가 API나 state 변수에서 온다면 null
이나 undefined
로 초기화될 수 있습니다. 그럴 경우 빈 문자열(''
)을 초깃값으로 설정하거나 value
가 문자열임을 보장하기 위해 value={someValue ?? ''}
를 전달하세요.
마찬가지로 체크박스에 checked
를 전달하는 경우 불리언임을 보장하세요.