内置浏览器<input>组件允许你渲染不同类型的表单输入。
<input />参考
<input>
要显示输入,请渲染内置浏览器<input>组件。
<input name="myInput" />属性
<input>支持所有通用元素属性。
formAction:字符串或函数。覆盖父级<form action>用于type="submit"和type="image"。当URL传递给action时,表单的行为将类似于标准HTML表单。当函数传递给formAction时,该函数将处理表单提交。参见<form action>。
你可以使输入受控,方法是传递以下属性之一
当你传递其中任何一个时,你还必须传递一个onChange处理程序来更新传递的值。
这些<input>属性仅与不受控制的输入相关
defaultChecked:布尔值。指定初始值用于type="checkbox"和type="radio"输入。defaultValue:字符串。指定文本输入的初始值。
这些<input> 属性与非受控输入和受控输入都相关。
accept:字符串。指定type="file"输入接受的文件类型。alt:字符串。为type="image"输入指定替代图像文本。capture:字符串。指定type="file"输入捕获的媒体(麦克风、视频或摄像头)。autoComplete:字符串。指定可能的自动完成行为之一。autoFocus:布尔值。如果为true,React 将在挂载时聚焦该元素。dirname:字符串。指定元素方向性的表单字段名称。disabled:布尔值。如果为true,则输入将不可交互,并显示为暗淡。children:<input>不接受子元素。form:字符串。指定此输入所属的<form>的id。如果省略,则为最近的父表单。formAction:字符串。覆盖父<form action>(针对type="submit"和type="image")。formEnctype:字符串。覆盖父<form enctype>(针对type="submit"和type="image")。formMethod:字符串。覆盖父<form method>(针对type="submit"和type="image")。formNoValidate:字符串。覆盖父<form noValidate>(针对type="submit"和type="image")。formTarget:字符串。覆盖父<form target>(针对type="submit"和type="image")。height:字符串。为type="image"指定图像高度。list:字符串。指定具有自动完成选项的<datalist>的id。max:数字。指定数值和日期时间输入的最大值。maxLength:数字。指定文本和其他输入的最大长度。min:数字。指定数值和日期时间输入的最小值。minLength:数字。指定文本和其他输入的最小长度。multiple:布尔值。指定是否允许为<type="file"和type="email"输入多个值。name:字符串。指定此输入的名称,该名称将与表单一起提交。onChange:一个Event处理器函数。对于受控输入是必需的。当用户更改输入的值时立即触发(例如,每次按键都会触发)。其行为类似于浏览器的input事件。onChangeCapture:onChange的一个版本,它在捕获阶段触发。onInput:一个Event处理器函数。当用户更改值时立即触发。出于历史原因,在 React 中习惯上使用onChange,其作用类似。onInputCapture:onInput的一个版本,它在捕获阶段触发。onInvalid:一个Event处理器函数。如果输入在表单提交时验证失败,则会触发。与内置的invalid事件不同,ReactonInvalid事件会冒泡。onInvalidCapture:onInvalid的一个版本,它在捕获阶段触发。onSelect:一个Event处理器函数。<input>内部的选择发生更改后触发。React 将onSelect事件扩展为也针对空选择和编辑(这可能会影响选择)触发。onSelectCapture:onSelect的一个版本,它在捕获阶段触发。pattern:字符串。指定value必须匹配的模式。placeholder:字符串。当输入值为空时,以暗淡的颜色显示。readOnly:布尔值。如果为true,则用户无法编辑输入。required:布尔值。如果为true,则必须提供值才能提交表单。size:数字。类似于设置宽度,但单位取决于控件。src:字符串。为type="image"输入指定图像源。step:正数或'any'字符串。指定有效值之间的距离。type:字符串。输入类型的其中之一。输入类型。width:字符串。为type="image"输入指定图像宽度。
注意事项
- 复选框需要
checked(或defaultChecked),而不是value(或defaultValue)。 - 如果文本输入接收一个字符串
value属性,它将被 视为受控组件。 - 如果复选框或单选按钮接收一个布尔值
checked属性,它将被 视为受控组件。 - 一个输入组件不能同时是受控和非受控的。
- 一个输入组件在其生命周期中不能在受控和非受控之间切换。
- 每个受控输入都需要一个
onChange事件处理程序,该程序同步更新其后备值。
使用方法
显示不同类型的输入
要显示输入框,请渲染一个 <input> 组件。默认情况下,它将是一个文本输入框。您可以传递 type="checkbox" 用于复选框,type="radio" 用于单选按钮,或其他输入类型之一。
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> 放入 <label> 标签内。这会告诉浏览器此标签与该输入相关联。当用户点击标签时,浏览器会自动将焦点放在输入框上。这对辅助功能也很重要:当用户将焦点放在关联的输入框上时,屏幕阅读器会宣布标签标题。
如果不能将 <input> 嵌套到 <label> 中,请通过将相同的 ID 传递给 <input id> 和 <label htmlFor> 来关联它们。为了避免一个组件的多个实例之间发生冲突,请使用 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" /> </> ); }
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> </> ); }
提交表单时读取输入值
将输入内容用`<form>标签包围,并在其中添加一个`<button type="submit">按钮。这将调用你的`<form onSubmit>事件处理器。默认情况下,浏览器会将表单数据发送到当前 URL 并刷新页面。你可以通过调用`e.preventDefault()来覆盖此行为。使用`new FormData(e.target)读取表单数据。
export default function MyForm() { function handleSubmit(e) { // Prevent the browser from reloading the page e.preventDefault(); // Read the form data const form = e.target; const formData = new FormData(form); // You can pass formData as a fetch body directly: fetch('/some-api', { method: form.method, body: formData }); // Or you can work with it as a plain 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> ); }
使用状态变量控制输入
像`<input />这样的输入是非受控的。即使你传递初始值,例如`<input defaultValue="Initial text" />,你的 JSX 仅指定初始值。它不会控制当前的值。
要渲染一个受控输入,请向其传递`value属性(对于复选框和单选按钮,则传递`checked属性)。React 将强制输入始终具有你传递的`value值。通常,你可以通过声明一个状态变量来实现这一点:
function Form() {
const [firstName, setFirstName] = useState(''); // Declare a state variable...
// ...
return (
<input
value={firstName} // ...force the input's value to match the state variable...
onChange={e => setFirstName(e.target.value)} // ... and update the state variable on any edits!
/>
);
}如果你需要状态(例如,在每次编辑时重新渲染 UI),受控输入就很有意义。
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>}
...如果你想提供多种调整输入状态的方法(例如,通过点击按钮),它也很有用。
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。如果需要初始值为empty(例如,下面的`firstName字段),请将状态变量初始化为空字符串(`'')。
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> } </> ); }
优化每次按键时的重新渲染
使用受控输入时,你每次按键都会设置状态。如果包含状态的组件重新渲染一个大型树,这可能会变慢。你可以通过几种方法来优化重新渲染性能。
例如,假设你从一个表单开始,该表单在每次按键时都会重新渲染所有页面内容。
function App() {
const [firstName, setFirstName] = useState('');
return (
<>
<form>
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</form>
<PageContent />
</>
);
}由于`<PageContent />不依赖于输入状态,你可以将输入状态移动到它自己的组件中。
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依赖于搜索输入的值),`useDeferredValue允许你即使在大型重新渲染过程中也能保持受控输入的响应性。
故障排除
我的文本输入框在输入时没有更新
如果你使用 value 属性渲染输入框,但是没有使用 onChange 属性,你将会在控制台看到错误。
// 🔴 Bug: controlled text input with no onChange handler
<input value={something} />value 属性,但没有提供 onChange 处理程序。这将渲染一个只读字段。如果字段应该是可变的,请使用 defaultValue。否则,请设置 onChange 或 readOnly。正如错误信息所示,如果你只想 指定初始值,请使用 defaultValue 属性。
// ✅ Good: uncontrolled input with an initial value
<input defaultValue={something} />如果你想 使用状态变量控制此输入框,请指定一个 onChange 处理程序。
// ✅ Good: controlled input with onChange
<input value={something} onChange={e => setSomething(e.target.value)} />如果值故意设置为只读,请添加 readOnly 属性来抑制错误。
// ✅ Good: readonly controlled input without on change
<input value={something} readOnly={true} />我的复选框在点击时没有更新
如果你使用 checked 属性渲染复选框,但是没有使用 onChange 属性,你将会在控制台看到错误。
// 🔴 Bug: controlled checkbox with no onChange handler
<input type="checkbox" checked={something} />checked 属性,但没有提供 onChange 处理程序。这将渲染一个只读字段。如果字段应该是可变的,请使用 defaultChecked。否则,请设置 onChange 或 readOnly。正如错误信息所示,如果你只想 指定初始值,请使用 defaultChecked 属性。
// ✅ Good: uncontrolled checkbox with an initial value
<input type="checkbox" defaultChecked={something} />如果你想 使用状态变量控制此复选框,请指定一个 onChange 处理程序。
// ✅ Good: controlled checkbox with onChange
<input type="checkbox" checked={something} onChange={e => setSomething(e.target.checked)} />如果复选框故意设置为只读,请添加 readOnly 属性来抑制错误。
// ✅ Good: readonly controlled input without on change
<input type="checkbox" checked={something} readOnly={true} />我的输入光标在每次按键时都跳到开头
如果你 控制一个输入框,你必须在 onChange 事件中将它的状态变量更新为 DOM 中输入框的值。
你不能将其更新为除了 e.target.value(或复选框的 e.target.checked)以外的值。
function handleChange(e) {
// 🔴 Bug: updating an input to something other than e.target.value
setFirstName(e.target.value.toUpperCase());
}你也不能异步地更新它。
function handleChange(e) {
// 🔴 Bug: updating an input asynchronously
setTimeout(() => {
setFirstName(e.target.value);
}, 100);
}要修复你的代码,请同步地将其更新为 e.target.value。
function handleChange(e) {
// ✅ Updating a controlled input to e.target.value synchronously
setFirstName(e.target.value);
}如果这不能解决问题,则可能是输入框在每次按键时都会从 DOM 中移除并重新添加。如果你在每次重新渲染时意外地 重置状态,例如,如果输入框或其父级总是接收不同的 key 属性,或者嵌套组件函数定义(这是不受支持的,并导致“内部”组件始终被认为是不同的树),就会发生这种情况。
我收到一个错误:“组件正在将不受控的输入更改为受控输入”
如果你为组件提供了一个 value 属性,它在其整个生命周期中必须保持为字符串。
你不能先传递 value={undefined},然后再传递 value="some string",因为 React 将无法知道你希望组件是不受控的还是受控的。受控组件应该始终接收一个字符串 value,而不是 null 或 undefined。
如果你的 value 来自 API 或状态变量,它可能被初始化为 null 或 undefined。在这种情况下,要么将其最初设置为空字符串 (''),要么传递 value={someValue ?? ''} 以确保 value 是一个字符串。
类似地,如果你将 checked 传递给复选框,请确保它始终是布尔值。