内置浏览器 <textarea> 组件 让你可以渲染多行文本输入。
🌐 The built-in browser <textarea> component lets you render a multiline text input.
<textarea />参考
🌐 Reference
<textarea>
要显示文本区域,请渲染 内置浏览器 <textarea> 组件。
🌐 To display a text area, render the built-in browser <textarea> component.
<textarea name="postContent" />属性
🌐 Props
<textarea> 支持所有 常用元素属性
你可以通过传递一个 value 属性来【使文本区域受控】(#controlling-a-text-area-with-a-state-variable):
🌐 You can make a text area controlled by passing a value prop:
value:一个字符串。控制文本区域内的文本。
当你传递 value 时,你还必须传递一个更新所传值的 onChange 处理器。
🌐 When you pass value, you must also pass an onChange handler that updates the passed value.
如果你的 <textarea> 无法控制,你可以传递 defaultValue 属性:
🌐 If your <textarea> is uncontrolled, you may pass the defaultValue prop instead:
defaultValue:一个字符串。指定文本区域的初始值。
这些 <textarea> 属性对于非受控和受控文本区域都相关:
🌐 These <textarea> props are relevant both for uncontrolled and controlled text areas:
autoComplete:'on'或'off'。指定自动补齐行为。autoFocus:一个布尔值。如果为true,React 会在挂载时聚焦该元素。children:<textarea>不接受子元素。要设置初始值,请使用defaultValue。cols:一个数字。指定平均字符宽度的默认宽度。默认值为20。disabled:一个布尔值。如果为true,输入将不可交互并且显示为灰色。form:一个字符串。指定此输入所属<form>的id。如果省略,则为最近的父表单。maxLength:一个数字。指定文本的最大长度。minLength:一个数字。指定文本的最小长度。name:一个字符串。指定此输入的名称,该名称会随表单一起提交。onChange:一个Event处理函数。在 受控文本区域 中是必需的。当用户更改输入的值时立即触发(例如,它在每次按键时都会触发)。行为类似于浏览器的input事件。onChangeCapture:onChange的一个版本,会在捕获阶段触发。onInput:一个Event处理函数。当值被用户更改时会立即触发。出于历史原因,在 React 中习惯使用onChange,它的作用类似。onInputCapture:onInput的一个版本,会在捕获阶段触发。onInvalid:一个Event处理程序函数。如果表单提交时输入验证失败,则会触发。与内置的invalid事件不同,React的onInvalid事件会冒泡。onInvalidCapture:onInvalid的一个版本,会在捕获阶段触发。onSelect:一个Event处理函数。在<textarea>内的选择发生变化后触发。React 扩展了onSelect事件,使其在空选择和编辑(可能影响选择)时也触发。onSelectCapture:onSelect的一个版本,会在捕获阶段触发。placeholder:一个字符串。当文本区域的值为空时,以灰色显示。readOnly:一个布尔值。如果true,文本区域不能被用户编辑。required:布尔值。如果true,则必须提供该值才能提交表单。rows:一个数字。指定平均字符高度的默认高度。默认值为2。wrap:可以是'hard'、'soft'或'off'。指定提交表单时文本的换行方式。
注意事项
🌐 Caveats
- 不允许传递像
<textarea>something</textarea>这样的子项。使用defaultValue作为初始内容。 - 如果文本区域接收到字符串
value属性,它将被视为受控的。 - 文本区域不能同时受控和不受控。
- 文本区域在其生命周期内无法在受控或不受控之间切换。
- 每个受控文本区域都需要一个
onChange事件处理程序,该处理程序同步更新其备份值。
用法
🌐 Usage
显示文本区域
🌐 Displaying a text area
将 <textarea> 渲染为显示文本区域。你可以使用 rows 和 cols 属性指定其默认大小,但默认情况下用户可以调整其大小。要禁用调整大小,可以在 CSS 中指定 resize: none。
🌐 Render <textarea> to display a text area. You can specify its default size with the rows and cols attributes, but by default the user will be able to resize it. To disable resizing, you can specify resize: none in the CSS.
export default function NewPost() { return ( <label> Write your post: <textarea name="postContent" rows={4} cols={40} /> </label> ); }
为文本区域提供标签
🌐 Providing a label for a text area
通常,你会将每个 <textarea> 放在 <label> 标签中。这告诉浏览器该标签与该文本区域相关联。当用户点击标签时,浏览器将会聚焦到文本区域。这对于可访问性也很重要:当用户聚焦文本区域时,屏幕阅读器会朗读标签标题。
🌐 Typically, you will place every <textarea> inside a <label> tag. This tells the browser that this label is associated with that text area. When the user clicks the label, the browser will focus the text area. It’s also essential for accessibility: a screen reader will announce the label caption when the user focuses the text area.
如果你不能将 <textarea> 嵌套到 <label> 中,可以通过将相同的 ID 传递给 <textarea id> 和 <label htmlFor>. 来关联它们。为了避免一个组件的多个实例之间发生冲突,可以使用 useId. 生成这样的 ID。
🌐 If you can’t nest <textarea> into a <label>, associate them by passing the same ID to <textarea id> and <label htmlFor>. To avoid conflicts between instances of one component, generate such an ID with useId.
import { useId } from 'react'; export default function Form() { const postTextAreaId = useId(); return ( <> <label htmlFor={postTextAreaId}> Write your post: </label> <textarea id={postTextAreaId} name="postContent" rows={4} cols={40} /> </> ); }
为文本区域提供初始值
🌐 Providing an initial value for a text area
你可以选择性地指定文本区域的初始值。将其作为 defaultValue 字符串传递。
🌐 You can optionally specify the initial value for the text area. Pass it as the defaultValue string.
export default function EditPost() { return ( <label> Edit your post: <textarea name="postContent" defaultValue="I really enjoyed biking yesterday!" rows={4} cols={40} /> </label> ); }
提交表单时读取文本区域值
🌐 Reading the text area value when submitting a form
在你的文本区域周围添加一个 <form>,里面放一个 <button type="submit">。它会调用你的 <form onSubmit> 事件处理程序。默认情况下,浏览器会将表单数据发送到当前 URL 并刷新页面。你可以通过调用 e.preventDefault() 来覆盖此行为。使用 new FormData(e.target) 读取表单数据。
export default function EditPost() { 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> Post title: <input name="postTitle" defaultValue="Biking" /> </label> <label> Edit your post: <textarea name="postContent" defaultValue="I really enjoyed biking yesterday!" rows={4} cols={40} /> </label> <hr /> <button type="reset">Reset edits</button> <button type="submit">Save post</button> </form> ); }
使用状态变量控制文本区域
🌐 Controlling a text area with a state variable
像 <textarea /> 这样的文本区域是不受控的。即使你传入一个初始值比如 <textarea defaultValue="Initial text" />,你的 JSX 仅仅指定了初始值,而不是当前的值。
🌐 A text area like <textarea /> is uncontrolled. Even if you pass an initial value like <textarea defaultValue="Initial text" />, your JSX only specifies the initial value, not the value right now.
要渲染一个_受控_的文本区域,请向其传递 value 属性。 React 将强制文本区域始终拥有你传递的 value。通常,你会通过声明一个 状态变量: 来控制文本区域。
function NewPost() {
const [postContent, setPostContent] = useState(''); // Declare a state variable...
// ...
return (
<textarea
value={postContent} // ...force the input's value to match the state variable...
onChange={e => setPostContent(e.target.value)} // ... and update the state variable on any edits!
/>
);
}如果你想要重新渲染 UI 的某些部分以响应每次击键,这将很有用。
🌐 This is useful if you want to re-render some part of the UI in response to every keystroke.
{ "dependencies": { "react": "latest", "react-dom": "latest", "react-scripts": "latest", "remarkable": "2.0.1" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" }, "devDependencies": {} }
故障排除
🌐 Troubleshooting
当我输入时,我的文本区域没有更新
🌐 My text area doesn’t update when I type into it
如果你用 value 渲染一个文本区域但没有 onChange,你将在控制台看到一个错误:
🌐 If you render a text area with value but no onChange, you will see an error in the console:
// 🔴 Bug: controlled text area with no onChange handler
<textarea value={something} />正如错误消息所示,如果你只想指定初始值, 请改为传入 defaultValue :
🌐 As the error message suggests, if you only wanted to specify the initial value, pass defaultValue instead:
// ✅ Good: uncontrolled text area with an initial value
<textarea defaultValue={something} />如果你想用状态变量控制这个文本区域,请指定一个 onChange 处理器:
🌐 If you want to control this text area with a state variable, specify an onChange handler:
// ✅ Good: controlled text area with onChange
<textarea value={something} onChange={e => setSomething(e.target.value)} />如果该值是有意只读的,请添加一个 readOnly 属性以抑制错误:
🌐 If the value is intentionally read-only, add a readOnly prop to suppress the error:
// ✅ Good: readonly controlled text area without on change
<textarea value={something} readOnly={true} />我的文本区域插入符在每次击键时跳到开头
🌐 My text area caret jumps to the beginning on every keystroke
如果你控制一个文本区域, 你必须在onChange期间将其状态变量更新为来自DOM中文本区域的值。
🌐 If you control a text area, you must update its state variable to the text area’s value from the DOM during onChange.
你无法将其更新为除了 e.target.value 以外的其他内容:
🌐 You can’t update it to something other than e.target.value:
function handleChange(e) {
// 🔴 Bug: updating an input to something other than e.target.value
setFirstName(e.target.value.toUpperCase());
}你也不能异步更新它:
🌐 You also can’t update it asynchronously:
function handleChange(e) {
// 🔴 Bug: updating an input asynchronously
setTimeout(() => {
setFirstName(e.target.value);
}, 100);
}要修复你的代码,请将其同步更新到 e.target.value:
🌐 To fix your code, update it synchronously to e.target.value:
function handleChange(e) {
// ✅ Updating a controlled input to e.target.value synchronously
setFirstName(e.target.value);
}如果这不能解决问题,那么很可能是在每次按键时,文本区域都会从 DOM 中被移除然后重新添加。如果你在每次重新渲染时不小心重置状态,就可能发生这种情况。例如,如果文本区域或其某个父元素总是收到不同的 key 属性,或者你嵌套了组件定义(在 React 中是不允许的,这会导致“内部”组件在每次渲染时重新挂载),就会出现这种情况。
🌐 If this doesn’t fix the problem, it’s possible that the text area gets removed and re-added from the DOM on every keystroke. This can happen if you’re accidentally resetting state on every re-render. For example, this can happen if the text area or one of its parents always receives a different key attribute, or if you nest component definitions (which is not allowed in React and causes the “inner” component to remount on every render).
我收到一个错误:“一个组件正在将不受控输入更改为受控输入”
🌐 I’m getting an error: “A component is changing an uncontrolled input to be controlled”
如果你向组件提供 value,它在整个生命周期中必须保持为字符串。
🌐 If you provide a value to the component, it must remain a string throughout its lifetime.
你不能先传入 value={undefined} 然后再传入 value="some string",因为 React 无法判断你是否希望组件是非受控的还是受控的。受控组件应该始终接收一个字符串 value,而不是 null 或 undefined。
🌐 You cannot pass value={undefined} first and later pass value="some string" because React won’t know whether you want the component to be uncontrolled or controlled. A controlled component should always receive a string value, not null or undefined.
如果你的 value 来自 API 或状态变量,它可能会被初始化为 null 或 undefined。在这种情况下,要么最初将其设置为空字符串(''),要么传递 value={someValue ?? ''} 来确保 value 是一个字符串。
🌐 If your value is coming from an API or a state variable, it might be initialized to null or undefined. In that case, either set it to an empty string ('') initially, or pass value={someValue ?? ''} to ensure value is a string.