Другое

Как условно добавлять атрибуты в React

Узнайте, как правильно условно добавлять атрибуты, такие как required и readOnly, к компонентам React. Узнайте, почему булевы значения работают лучше строковых, и избегайте распространенных ошибок при рендеринге элементов форм.

Как условно добавлять атрибуты к React компонентам?

Мне нужно условно добавлять атрибуты, такие как required и readOnly, к элементам форм в React на основе определенных условий. Конкретно, я пытаюсь добавлять эти атрибуты после вызова Ajax, который рендерит компонент, но я столкнулся с проблемой, потому что установка readOnly="false" не эквивалентна полному отсутствию атрибута.

Например, этот код работает не так, как ожидалось:

javascript
function MyInput({isRequired}) {
  return <input classname="foo" {isRequired ? "required" : ""} />
}

Как правильно условно добавлять или опускать атрибуты в React компонентах?

Обработка булевых атрибутов в React

Компоненты React обрабатывают булевы атрибуты иначе, чем строковые. Для атрибутов required и readOnly следует передавать их в виде булевых значений, а не строк. Ключевой момент заключается в том, что React опускает атрибуты, когда они установлены в false, null или undefined, но включает их, когда установлены в true. Установка readOnly="false" создает атрибут со значением “false”, а не опускает его полностью.

Содержание


Понимание обработки атрибутов в React

React обрабатывает атрибуты по-разному в зависимости от их типа. Для булевых атрибутов, таких как required и readOnly, React следует определенным правилам:

  • При установке в true атрибут включается в DOM
  • При установке в false, null или undefined атрибут полностью опускается
  • Строковые атрибуты ведут себя иначе - им требуются явные значения

Это поведение является намеренным и помогает поддерживать DOM в чистоте. Как объясняется на Sentry.io: “Если атрибут компонента хоста React установлен в null, undefined или false, React не передаст этот атрибут элементу DOM.”

jsx
// Правильно - обработка булевых атрибутов
<input required={true} />          // Рендерится как <input required>
<input required={false} />         // Рендерится как <input> (атрибут required отсутствует)
<input required={undefined} />     // Рендерится как <input> (атрибут required отсутствует)
<input required={null} />          // Рендерится как <input> (атрибут required отсутствует)

// Неправильно - обработка строковых атрибутов
<input required="true" />          // Рендерится как <input required="true">
<input required="false" />         // Рендерится как <input required="false">

Булевы атрибуты в React

Булевы атрибуты в React имеют специфические требования:

Атрибут readOnly

React ожидает readOnly (с заглавной ‘O’), а не readonly. Это является распространенным источником путаницы.

jsx
// Правильно
<input readOnly={true} />          // Рендерится как <input readOnly>

// Неправильно
<input readonly={true} />          // Может работать не так, как ожидается

Атрибут required

Атрибут required следует тому же булевому шаблону:

jsx
// Правильное условное использование
<input required={isRequired} />    // Если is равно true, рендерится <input required>
                                  // Если is равно false, рендерится <input>

Согласно документации React, это булевы атрибуты: “Если true, поле ввода не может быть изменено пользователем” для readOnly, и “Если true, значение должно быть предоставлено для отправки формы” для required.


Лучшие практики для элементов форм

Базовые условные атрибуты

Для вашего конкретного случая использования с элементами форм, вот правильные подходы:

jsx
function MyInput({isRequired, isReadOnly}) {
  return (
    <input 
      className="foo"
      required={isRequired}
      readOnly={isReadOnly}
    />
  )
}

// Использование
<MyInput isRequired={true} isReadOnly={false} />  // Присутствует только атрибут required
<MyInput isRequired={false} isReadOnly={true} />  // Присутствует только атрибут readOnly
<MyInput isRequired={true} isReadOnly={true} />   // Присутствуют оба атрибута
<MyInput isRequired={false} isReadOnly={false} /> // Нет булевых атрибутов

После AJAX-вызовов

Когда вам нужно установить атрибуты после AJAX-вызова, убедитесь, что вы используете состояние:

jsx
function MyForm() {
  const [formData, setFormData] = useState({
    isRequired: false,
    isReadOnly: false
  });

  useEffect(() => {
    // Имитация AJAX-вызова
    fetchFormData().then(data => {
      setFormData({
        isRequired: data.isRequired,
        isReadOnly: data.isReadOnly
      });
    });
  }, []);

  return (
    <input 
      className="foo"
      required={formData.isRequired}
      readOnly={formData.isReadOnly}
    />
  );
}

Шаблоны условных атрибутов

Подход с тернарным оператором

Как рекомендуют различные источники, тернарный оператор - это чистый способ обработки условных атрибутов:

jsx
function MyInput({isRequired}) {
  return (
    <input 
      className="foo"
      required={isRequired ? true : undefined}
    />
  );
}

Шаблон с spread объекта

Для нескольких условных атрибутов можно использовать spread объекта:

jsx
function MyInput({props}) {
  const inputProps = {
    className: "foo",
    ...props.isRequired && { required: true },
    ...props.isReadOnly && { readOnly: true }
  };

  return <input {...inputProps} />;
}

// Использование
<MyInput 
  props={{ 
    isRequired: true, 
    isReadOnly: false 
  }} 
/>

Пользовательский хук для повторного использования

Для сложных приложений создайте пользовательский хук:

jsx
function useConditionalAttribute(condition) {
  return condition ? true : undefined;
}

function MyInput({isRequired, isReadOnly}) {
  return (
    <input 
      className="foo"
      required={useConditionalAttribute(isRequired)}
      readOnly={useConditionalAttribute(isReadOnly)}
    />
  );
}

Распространенные ошибки и решения

Ошибка 1: Использование строковых значений

jsx
// ❌ Неправильно - создает атрибут со значением "false"
<input required="false" readOnly="false" />

// ✅ Правильно - опускает атрибуты при false
<input required={false} readOnly={false} />

Ошибка 2: Неправильное имя атрибута

jsx
// ❌ Неправильно - строчная 'o'
<input readonly={true} />

// ✅ Правильно - заглавная 'O'
<input readOnly={true} />

Ошибка 3: Пустая строка для булевых атрибутов

jsx
// ❌ Неправильно - не работает как ожидается
<input required="" readOnly="" />

// ✅ Правильно - используйте булевы значения
<input required={false} readOnly={false} />

Расширенное решение: Динамическая обработка атрибутов

Для сложных сценариев, где может быть много условных атрибутов:

jsx
function MyInput({attributes}) {
  const inputProps = {
    className: "foo",
    ...Object.entries(attributes).reduce((acc, [key, value]) => {
      if (value) {
        acc[key] = true;
      }
      return acc;
    }, {})
  };

  return <input {...inputProps} />;
}

// Использование
<MyInput 
  attributes={{ 
    required: true, 
    readOnly: false,
    disabled: true 
  }} 
/>

Источники

  1. Как условно добавлять атрибуты к компонентам React? - Stack Overflow
  2. Освоение атрибутов readOnly ввода в React: лучшие практики - Dhiwise
  3. reactjs - Какой лучший способ условно добавить readOnly в React? - Stack Overflow
  4. Топ-4 способа условного добавления атрибутов к компонентам React - SQLPey
  5. Как условно добавлять атрибуты к компонентам React? - Sentry
  6. – Документация React
  7. Атрибут элемента DOM React не должен иметь значения - DeepScan

Заключение

  • Булевы атрибуты в React должны передаваться в виде булевых значений, а не строк. Используйте true для включения и false, null или undefined для опускания атрибутов.
  • Всегда используйте readOnly (с заглавной O) для атрибута “только для чтения” в React, а не readonly.
  • Тернарный оператор является рекомендуемым подходом для условного рендеринга атрибутов: {condition ? true : undefined}.
  • После AJAX-вызовов управляйте булевыми атрибутами через состояние React для обеспечения правильного перерисовки.
  • Избегайте распространенных ошибок, таких как использование строковых значений (“false”) или неправильных имен атрибутов, что может привести к неожиданному поведению DOM.

Следуя этим практикам, вы обеспечите корректное поведение элементов форм и поддержите чистые, эффективные структуры DOM.

Авторы
Проверено модерацией
Модерация