Формы могут быть сложной частью приложения React. Хотя было бы неплохо иметь единый способ создания формы, формы также должны быть настраиваемыми. Формы могут иметь разные стили, использовать разные методы проверки и отправляться по-разному (например, в конечную точку API или обычную отправку формы). В нашем приложении мы испробовали несколько способов структурирования форм, и теперь каждая форма обрабатывает эти проблемы немного по-своему. Мы решили придумать решение, которое можно было бы использовать во всем приложении, которое будет достаточно гибким, чтобы обрабатывать различные случаи, но также обеспечит полезную функциональность.

Используемый нами шаблон известен в некоторых местах как функция как дочерний компонент. Некоторые назвали это антипаттерном, но другие утверждали, что это более способно, чем обычные, утомительные старые компоненты более высокого порядка. На данный момент это работает. Может быть, однажды мы осознаем ошибочность наших методов и реорганизуем ее в соответствии с новым классным паттерном будущего. Но сегодня не тот день.

Нам нужен минималистичный компонент, который делает за нас несколько вещей:

  1. Устанавливает значения по умолчанию для каждого поля и отслеживает любые изменения, и если они были затронуты.
  2. Возвращает объект с сообщениями об ошибках.
  3. Отслеживает, действительна ли форма для отправки.
  4. Предоставляет функцию, которую можно использовать для вызова функции отправки.

Базовая схема функции выглядит так:

<FormContainer fieldDefaults={fieldDefaults} errorFuncs={errorFuncs}
  onSubmit={onSubmit}>
  {({ fields, errorValues, triggerSubmit, submitDisabled }) => {
    return(...)
  }}
</FormContainer>

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

Определение компонента довольно простое. Настройка состояния - это немного сложно, поэтому я объясню это подробно.

state = {
  fields: {
    ...Object.keys(this.props.fieldDefaults).reduce((acc, curr) => (
      {
        ...acc,
        [curr]: {
          value: this.props.fieldDefaults[curr],
          isDirty: false,
        },
      }
    ), {}),
  },
  errorFuncs: this.props.errorFuncs,
}

Чтобы понять, что здесь происходит, вам нужно понять две вещи. Во-первых, функция уменьшения, с которой вы можете ознакомиться здесь. Во-вторых, деструктуризация объекта, о которой вы можете узнать здесь.

По сути, это устанавливает начальное состояние формы. Контейнер отправляется в объекте с парами "ключ-значение", состоящими из имени поля и начального значения этого поля. Эта функция создает объект с ключом «field» с объектом для каждого поля внутри. Каждый объект поля имеет значение (которое передается контейнеру) и начальное значение isDirty (ложь). Значение isDirty используется, чтобы контейнер знал, было ли поле изменено пользователем, поэтому до этого момента ошибки не появятся. После запуска функции состояние может выглядеть примерно так:

{
  fields: {
    firstName: {
      value: '',
      isDirty: false,
    },
    lastName: {
      value: '',
      isDirty: false,
    },
    email: {
      value: '',
      isDirty: false,
    },
  },
  errorFuncs: { ... }
}

Компонент форматирует данные, которые он отправит обратно, и отправляет их, отображая своих дочерних элементов с параметрами:

return (
  this.props.children({
    fields, errorValues, onChange, triggerSubmit, submitDisabled
  })
);

Функция onChange устанавливает новое значение поля в состоянии и устанавливает для поля «isDirty» значение true.

Такое решение форм React дает вам полный контроль над тем, как форма отображается, но вы по-прежнему получаете проверку, ошибки и все преимущества контролируемой формы. Мы уже некоторое время используем этот компонент для наших форм, и мне понравились его простота и последовательность.

Что бы вы сделали по-другому? Дайте мне знать, я всегда стремлюсь стать лучше!