内置浏览器<textarea>组件允许您渲染多行文本输入。
<textarea />参考
<textarea>
要显示文本区域,请渲染内置浏览器<textarea>组件。
<textarea name="postContent" />属性
<textarea> 支持所有通用元素属性。
您可以使文本区域受控,方法是传递一个value属性
value:字符串。控制文本区域内的文本。
当您传递value时,您还必须传递一个onChange处理程序来更新传递的值。
如果您的<textarea>不受控,您可以改为传递defaultValue属性
defaultValue:字符串。指定文本区域的初始值。
这些<textarea>属性与不受控和受控文本区域都相关
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事件不同,ReactonInvalid事件会冒泡。onInvalidCapture:onInvalid的一个版本,它在捕获阶段触发。onSelect:一个Event处理程序函数。<textarea>内部的选择发生变化后触发。React 扩展了onSelect事件,使其也适用于空选择和编辑(这可能会影响选择)。onSelectCapture:onSelect的一个版本,它在捕获阶段触发。placeholder:字符串。当文本区域值为空时,以灰暗的颜色显示。readOnly:布尔值。如果为true,则用户无法编辑文本区域。required:布尔值。如果为true,则必须提供值才能提交表单。rows:数字。指定默认高度(以平均字符高度为单位)。默认为2。wrap:'hard','soft'或'off'。指定提交表单时如何换行。
注意事项
- 不允许像
<textarea>something</textarea>这样传递子元素。 请使用defaultValue属性设置初始内容。 - 如果文本区域接收字符串
value属性,它将被 视为受控组件。 - 文本区域不能同时是受控组件和非受控组件。
- 文本区域在其生命周期内不能在受控和非受控状态之间切换。
- 每个受控文本区域都需要一个
onChange事件处理程序,该程序同步更新其后台值。
用法
显示文本区域
渲染 <textarea> 来显示文本区域。您可以使用 rows 和 cols 属性指定其默认大小,但默认情况下用户可以调整其大小。要禁用调整大小,可以在 CSS 中指定 resize: none。
export default function NewPost() { return ( <label> Write your post: <textarea name="postContent" rows={4} cols={40} /> </label> ); }
为文本区域提供标签
通常,您会将每个 <textarea> 元素放在 <label> 标签内。这会告诉浏览器此标签与该文本区域相关联。当用户单击标签时,浏览器将聚焦文本区域。这对于辅助功能也很重要:当用户聚焦文本区域时,屏幕阅读器会宣布标签标题。
如果您不能将 <textarea> 嵌套到 <label> 中,请通过将相同的 ID 传递给 <textarea id> 和 <label htmlFor> 来关联它们。为避免一个组件的实例之间发生冲突,请使用 useId 生成此类 ID。
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} /> </> ); }
export default function EditPost() { return ( <label> Edit your post: <textarea name="postContent" defaultValue="I really enjoyed biking yesterday!" rows={4} cols={40} /> </label> ); }
提交表单时读取文本区域的值
在您的文本区域周围添加一个 <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> ); }
使用状态变量控制文本区域
像 `<textarea /> 这样的文本区域是非受控的。即使你传递初始值,例如 `<textarea defaultValue="Initial text" />,你的 JSX 只指定了初始值,而不是当前值。
要渲染一个受控的文本区域,请向其传递 `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 的一部分,这将非常有用。
{ "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": {} }
故障排除
我的文本区域在输入时没有更新
如果你使用 `value 属性但没有使用 `onChange 属性来渲染文本区域,你将在控制台中看到一个错误。
// 🔴 Bug: controlled text area with no onChange handler
<textarea value={something} />value 属性,但没有提供 `onChange 处理程序。这将渲染一个只读字段。如果字段应该是可变的,请使用 `defaultValue。否则,请设置 `onChange 或 `readOnly 属性。正如错误消息所示,如果你只想指定初始值,请传递 `defaultValue 属性。
// ✅ Good: uncontrolled text area with an initial value
<textarea defaultValue={something} />如果你想使用状态变量来控制此文本区域,请指定一个 `onChange 处理程序。
// ✅ Good: controlled text area with onChange
<textarea value={something} onChange={e => setSomething(e.target.value)} />如果该值故意设置为只读,请添加 `readOnly 属性以抑制错误。
// ✅ Good: readonly controlled text area without on change
<textarea value={something} readOnly={true} />我的文本区域光标在每次按键时都跳到开头
如果您控制文本区域,则必须在onChange事件期间,将文本区域的值从DOM更新到其状态变量。
您不能将其更新为除e.target.value之外的其他值。
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属性,或者嵌套组件定义(React中不允许这样做,并且会导致“内部”组件在每次渲染时重新挂载),则会发生这种情况。
我收到一个错误:“组件正在将不受控输入更改为受控输入”
如果您向组件提供value,则它在其整个生命周期中必须保持为字符串。
您不能先传递value={undefined},然后传递value="some string",因为React无法知道您是想让组件不受控还是受控。受控组件应始终接收字符串value,而不是null或undefined。
如果您的value来自API或状态变量,则它可能被初始化为null或undefined。在这种情况下,最初将其设置为空字符串(''),或者传递value={someValue ?? ''}以确保value是字符串。