内置浏览器 <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 事件
  • onChangeCaptureonChange 的一个版本,在 捕获阶段触发。
  • onInput:一个 Event 处理程序 函数。 当用户的操作导致值发生更改时立即触发。 出于历史原因,在 React 中习惯上使用 onChange 来代替它,其工作原理类似。
  • onInputCaptureonInput 的一个版本,在 捕获阶段触发。
  • onInvalid:一个 Event 处理程序 函数。 如果输入在表单提交时未通过验证,则触发。 与内置的 invalid 事件不同,React 的 onInvalid 事件会冒泡。
  • onInvalidCaptureonInvalid 的一个版本,在 捕获阶段触发。
  • onSelect:一个 Event 处理程序 函数。 在 <textarea> 内的选区发生变化后触发。 React 扩展了 onSelect 事件,使其在空选择和编辑(可能会影响选区)时也会触发。
  • onSelectCaptureonSelect 的一个版本,在 捕获阶段触发。
  • placeholder:一个字符串。 当文本区域值为空时,以灰色显示。
  • readOnly:一个布尔值。如果为 true,则用户无法编辑文本区域。
  • required:一个布尔值。如果为 true,则必须提供值才能提交表单。
  • rows:一个数字。指定默认高度(以平均字符高度为单位)。 默认为 2
  • wrap'hard''soft''off' 之一。 指定提交表单时应如何换行文本。

注意事项

  • 不允许像 <textarea>something</textarea> 这样传递子元素。 请使用 defaultValue 设置初始内容。
  • 如果文本区域接收到字符串 value 属性,它将被 视为受控的。
  • 文本区域不能同时是受控的和不受控的。
  • 文本区域在其生命周期内不能在受控和不受控之间切换。
  • 每个受控文本区域都需要一个 onChange 事件处理程序,该处理程序同步更新其支持值。

用法

显示文本区域

渲染 <textarea> 以显示文本区域。您可以使用 rowscols 属性指定其默认大小,但默认情况下用户可以调整其大小。要禁用调整大小,您可以在 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}
      />
    </>
  );
}


为文本区域提供初始值

您可以选择为文本区域指定初始值。将其作为 defaultValue 字符串传递。

export default function EditPost() {
  return (
    <label>
      Edit your post:
      <textarea
        name="postContent"
        defaultValue="I really enjoyed biking yesterday!"
        rows={4}
        cols={40}
      />
    </label>
  );
}

陷阱

与 HTML 不同,不支持传递像 <textarea>一些内容</textarea> 这样的初始文本。


提交表单时读取文本区域值

在您的文本区域周围添加一个 <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> 指定一个 name,例如 <textarea name="postContent" />。您指定的 name 将用作表单数据中的键,例如 { postContent: "您的帖子" }

陷阱

默认情况下,<form> 内部的 *任何* <button> 都会提交它。这可能会让人感到意外!如果您有自己的自定义 Button React 组件,请考虑返回 <button type="button"> 而不是 <button>。然后,为了明确起见,请对 *应该* 提交表单的按钮使用 <button type="submit">


使用状态变量控制文本区域

<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,则无法在文本区域中键入内容。 当您通过传递某个 value 来控制文本区域时,您就 *强制* 它始终具有您传递的值。因此,如果您传递一个状态变量作为 value,但忘记在 onChange 事件处理程序中同步更新该状态变量,React 将在每次按键后将文本区域恢复为您指定的 value


故障排除

我的文本区域在我输入时不会更新

如果使用 value 渲染文本区域但没有 onChange,您将在控制台中看到一个错误

// 🔴 Bug: controlled text area with no onChange handler
<textarea value={something} />
控制台
您向表单字段提供了一个 value 属性,但没有提供 onChange 处理程序。这将渲染一个只读字段。如果该字段应该是可变的,请使用 defaultValue。否则,请设置 onChangereadOnly

正如错误消息所建议的,如果您只想 指定 *初始* 值, 请改用 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,而不是 nullundefined

如果您的 value 来自 API 或状态变量,则它最初可能会被初始化为 nullundefined。在这种情况下,请在最初将其设置为空字符串 (''),或者传递 value={someValue ?? ''} 以确保 value 是字符串。