Перейти к содержанию

<textarea>

Встроенный компонент браузера <textarea> позволяет отображать многострочный текстовый ввод.

1
<textarea />

Описание

<textarea>

Чтобы отобразить текстовую область, создайте компонент встроенный в браузер <textarea>.

1
<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: Строка. Указывает id <form>, к которой принадлежит этот ввод. Если опущено, то это ближайшая родительская форма.
  • maxLength: Число. Определяет максимальную длину текста.
  • minLength: Число. Определяет минимальную длину текста.
  • name: Строка. Задает имя для этого ввода, который передается вместе с формой.
  • onChange: Функция обработчика event. Требуется для управляемых текстовых областей. Срабатывает немедленно, когда значение ввода изменяется пользователем (например, срабатывает при каждом нажатии клавиши). Поведение аналогично браузерному событию input.
  • onChangeCapture: Версия onChange, которая срабатывает в фазе захвата.
  • onInput: Функция обработчика event. функция. Срабатывает немедленно, когда значение изменяется пользователем. По историческим причинам в React идиоматично использовать onChange, которая работает аналогично.
  • onInputCapture: Версия onInput, которая срабатывает в фазе захвата.
  • onInvalid: Функция обработчика event. Срабатывает, если ввод не прошел валидацию при отправке формы. В отличие от встроенного события invalid, событие React onInvalid всплывает.
  • onInvalidCapture: Версия onInvalid, которая срабатывает в фазе захвата.
  • onSelect: Функция обработчика Event handler. Срабатывает после изменения выделения внутри <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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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>. Чтобы избежать конфликтов между экземплярами одного компонента, создайте такой ID с помощью useId.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
export default function EditPost() {
    return (
        <label>
            Edit your post:
            <textarea
                name="postContent"
                defaultValue="I really enjoyed biking yesterday!"
                rows={4}
                cols={40}
            />
        </label>
    );
}

Содержимое <textarea>...</textarea>

В отличие от HTML, передача начального текста типа <textarea>Some content</textarea> не поддерживается.

Чтение значения текстовой области при отправке формы

Добавьте <form> вокруг вашей текстовой области с <button type="submit"> внутри. Это вызовет обработчик события <form onSubmit>. По умолчанию браузер отправит данные формы на текущий URL и обновит страницу. Вы можете отменить это поведение, вызвав e.preventDefault(). Считайте данные формы с помощью new FormData(e.target).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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>
    );
}

Дайте name вашему <textarea>

Дайте name вашему <textarea>, например <textarea name="postContent" />. Указанное вами name будет использоваться в качестве ключа в данных формы, например { postContent: "Ваш пост" }.

Тип button

По умолчанию любая <button> внутри <form> отправит ее. Это может быть неожиданно! Если у вас есть собственный пользовательский компонент React Button, подумайте о возврате <button type="button"> вместо <button>. Затем, чтобы быть явным, используйте <button type="submit"> для кнопок, которые должны отправлять форму.

Управление текстовой областью с помощью переменной состояния

Текстовая область типа <textarea /> является неуправляемой. Даже если вы передадите начальное значение, например <textarea defaultValue="Initial text" />, ваш JSX определяет только начальное значение, а не значение прямо сейчас.

Чтобы отобразить управляемую текстовую область, передайте ей свойство value. React заставит текстовую область всегда иметь переданное вами value. Обычно вы управляете текстовой областью, объявляя переменную состояния:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function NewPost() {
    // Declare a state variable...
    const [postContent, setPostContent] = useState('');
    // ...
    return (
        <textarea
            // ...force the input's value to match the state variable...
            value={postContent}
            // ... and update the state variable on any edits!
            onChange={(e) => setPostContent(e.target.value)}
        />
    );
}

Это полезно, если вы хотите перерисовывать часть пользовательского интерфейса в ответ на каждое нажатие клавиши.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { useState } from 'react';
import MarkdownPreview from './MarkdownPreview.js';

export default function MarkdownEditor() {
    const [postContent, setPostContent] = useState(
        '_Hello,_ **Markdown**!'
    );
    return (
        <>
            <label>
                Enter some markdown:
                <textarea
                    value={postContent}
                    onChange={(e) =>
                        setPostContent(e.target.value)
                    }
                />
            </label>
            <hr />
            <MarkdownPreview markdown={postContent} />
        </>
    );
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import { Remarkable } from 'remarkable';

const md = new Remarkable();

export default function MarkdownPreview({ markdown }) {
    const renderedHTML = md.render(markdown);
    return (
        <div
            dangerouslySetInnerHTML={{
                __html: renderedHTML,
            }}
        />
    );
}

Если вы передадите value без onChange, в текстовой области будет невозможно набирать текст

Когда вы управляете текстовой областью, передавая ей некоторое value, вы принуждаете ее всегда иметь то значение, которое вы передали. Поэтому если вы передадите переменную состояния в качестве значения, но забудете синхронно обновить эту переменную состояния в обработчике события onChange, React будет возвращать текстовую область после каждого нажатия клавиши к указанному вами значению.

Устранение неполадок

Моя текстовая область не обновляется, когда я ввожу текст

Если вы отображаете текстовую область с value, но без onChange, вы увидите ошибку в консоли:

1
2
// 🔴 Bug: controlled text area with no onChange handler
<textarea value={something} />

Ошибка

Вы предоставили свойство value полю формы без обработчика onChange. Это приведет к тому, что поле будет доступно только для чтения. Если поле должно быть изменяемым, используйте defaultValue. В противном случае установите либо onChange, либо readOnly.

Как следует из сообщения об ошибке, если вы хотите указать только начальное значение, передайте defaultValue вместо этого:

1
2
// ✅ Good: uncontrolled text area with an initial value
<textarea defaultValue={something} />

Если вы хотите управлять этой текстовой областью с помощью переменной состояния, укажите обработчик onChange:

1
2
3
4
5
// ✅ Good: controlled text area with onChange
<textarea
    value={something}
    onChange={(e) => setSomething(e.target.value)}
/>

Если значение намеренно предназначено только для чтения, добавьте параметр readOnly, чтобы подавить ошибку:

1
2
// ✅ Good: readonly controlled text area without on change
<textarea value={something} readOnly={true} />

Моя текстовая область переходит в начало при каждом нажатии клавиши

Если вы управляете текстовой областью, вы должны обновить ее переменную состояния до значения текстовой области из DOM во время onChange.

Вы не можете обновить ее до значения, отличного от e.target.value:

1
2
3
4
function handleChange(e) {
    // 🔴 Bug: updating an input to something other than e.target.value
    setFirstName(e.target.value.toUpperCase());
}

Вы также не можете обновлять его асинхронно:

1
2
3
4
5
6
function handleChange(e) {
    // 🔴 Bug: updating an input asynchronously
    setTimeout(() => {
        setFirstName(e.target.value);
    }, 100);
}

Чтобы исправить свой код, обновите его синхронно с e.target.value:

1
2
3
4
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 является строкой.

Источник — https://react.dev/reference/react-dom/components/textarea

Комментарии