React: интересная схема работы с формами

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.


Hello, world!


В этой статье я хочу рассказать о схеме (назовем ее так) работы с формами в React, которая на сегодняшний день кажется мне наиболее эффективной. Эта схема предполагает использование React Hook Form для обработки форм и Zod для валидации пользовательских данных. Применение данной схемы имеет несколько существенных преимуществ по сравнению с использованием других решений или реализацией необходимого функционала вручную. Главными преимуществами являются минимизация количества шаблонного кода и автоматическое выведение типов (type inference).


Для тех, кого интересует только код, вот ссылка на соответствующий репозиторий.


Интересно? Тогда прошу под кат.


В качестве примера разработаем простую форму регистрации, содержащую следующие поля:


  • имя пользователя;
  • возраст;
  • адрес электронной почты;
  • пароль;
  • подтверждение пароля.

А также индикатор (чекбокс) принятия неких условий использования.


Все поля будут обязательными. О конкретных требованиях к каждому полю поговорим немного позднее.


Подготовка, настройка проекта и создание формы


Создаем шаблон проекта React с поддержкой TypeScript с помощью Vite (для работы с зависимостями я буду использовать Yarn):


# react-hook-form-zod - название проекта
# react-ts - используемый шаблон
yarn create vite react-hook-form-zod --template react-ts

Переходим в созданную директорию, устанавливаем зависимости и запускаем сервер для разработки:


cd react-hook-form-zod
yarn
yarn dev

Наша форма должна быть приятной глазу. Что бы нам использовать для ее стилизации? Как насчет Tailwind CSS? Устанавливаем эту библиотеку в качестве зависимости для разработки:


yarn add -D tailwindcss

Инициализируем ее:


npx tailwindcss init

Импортируем стили tailwind и определяем несколько переиспользуемых (reusable) стилей с помощью директивы @apply в файле src/index.css:


@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .title {
    @apply text-2xl text-center font-bold leading-tight tracking-tight text-gray-900;
  }
  .label {
    @apply block mb-2 text-sm font-medium text-gray-900 cursor-pointer;
  }
  .input {
    @apply bg-gray-50 border-none outline outline-1 outline-gray-300 text-gray-900 rounded-md w-full p-2.5 focus-visible:outline-2 focus-visible:outline-blue-500 placeholder:text-sm aria-[invalid="true"]:outline-red-500 aria-[invalid="true"]:outline-2;
    transition: outline-color 150ms cubic-bezier(0.4, 0, 0.2, 1);
  }
  .error {
    @apply text-red-600 block text-sm absolute;
  }
  .btn {
    @apply text-white outline-none focus:ring-4 font-medium rounded-md text-sm px-5 py-2.5 text-center transition-colors disabled:opacity-50 disabled:cursor-not-allowed;
  }
  .btn-primary {
    @apply bg-primary-500 hover:bg-primary-700 focus:ring-primary-300 disabled:bg-primary-500;
  }
  .btn-error {
    @apply bg-red-500 hover:bg-red-700 focus:ring-red-300 disabled:bg-red-500;
  }
}

Определяем файлы для обработки и расширяем дефолтную цветовую схему tailwind в файле tailwind.config.cjs:


/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./src/**/*.{js,jsx,ts,tsx}'],
  theme: {
    extend: {
      colors: {
        primary: {
          50: '#eff6ff',
          100: '#dbeafe',
          200: '#bfdbfe',
          300: '#93c5fd',
          400: '#60a5fa',
          500: '#3b82f6',
          600: '#2563eb',
          700: '#1d4ed8',
          800: '#1e40af',
          900: '#1e3a8a'
        }
      }
    }
  },
  plugins: []
}

Наконец, определяем форму в файле src/App.tsx:


function App() {
  return (
    <section className='bg-gray-50'>
      <div className='flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0'>
        <div className='w-full bg-white rounded-lg shadow md:mt-0 sm:max-w-md xl:p-0'>
          <div className='p-6 space-y-4 md:space-y-6 sm:p-8'>
            <h1 className='title'>Создание аккаунта</h1>
            <form className='space-y-7'>
              <div className='mb-4'>
                <label htmlFor='username' className='label'>
                  Имя пользователя *
                </label>
                <input
                  type='text'
                  id='username'
                  className='input'
                  placeholder='Ваше имя'
                />
              </div>
              <div className='mb-4'>
                <label htmlFor='age' className='label'>
                  Возраст
                </label>
                <input
                  type='number'
                  id='age'
                  className='input'
                  placeholder='От 18 до 65 лет'
                />
              </div>
              <div>
                <label htmlFor='email' className='label'>
                  Адрес электронной почты *
                </label>
                <input
                  type='email'
                  id='email'
                  className='input'
                  placeholder='name@mail.com'
                />
              </div>
              <div>
                <label htmlFor='password' className='label'>
                  Пароль *
                </label>
                <input
                  type='password'
                  id='password'
                  placeholder='Не менее 6 символов'
                  className='input'
                />
              </div>
              <div>
                <label htmlFor='confirmPassword' className='label'>
                  Подтверждение пароля *
                </label>
                <input
                  type='password'
                  id='confirmPassword'
                  placeholder='Не менее 6 символов'
                  className='input'
                />
              </div>
              <div className='flex items-center relative'>
                <input
                  id='terms'
                  aria-describedby='terms'
                  type='checkbox'
                  className='w-4 h-4 border border-gray-300 bg-gray-50 accent-primary-500 focus:outline-2 focus:outline-primary-500 outline-none'
                />
                <label
                  htmlFor='terms'
                  className='font-light text-gray-500 text-sm ml-3 cursor-pointer select-none'
                >
                  Я принимаю{' '}
                  <a
                    className='font-medium text-primary-500 hover:text-primary-700 focus:text-primary-700 transition-colors outline-none'
                    href='#'
                  >
                    Условия использования
                  </a>
                </label>
              </div>
              <div className='flex gap-5 justify-center pt-2'>
                <button
                  type='submit'
                  className='btn btn-primary'
                >
                  Создать аккаунт
                </button>
                <button
                  type='button'
                  className='btn btn-error'
                >
                  Очистить поля
                </button>
              </div>
            </form>
          </div>
        </div>
      </div>
    </section>
  )
}

export default App

Результат:





Кроме названных выше полей, форма содержит кнопки для отправки формы ("Создать аккаунт") и очистки всех полей ("Очистить поля"). Она выглядит прилично (по крайней мере, на мой "вкус и цвет"

Источник: https://habr.com/ru/company/timeweb/blog/722108/


Интересные статьи

Интересные статьи

Продолжаем изучение внешнего RS485/ModbusRTU блока расширения MA01-AACX2240 компании EBYTE. Сегодня мы разберём устройство Modbus RTU регистров, принципов доступа к ним и получения информации от M...
Всем привет. Текст состоит из двух частей:1. Небольшая шпаргалка по параметрам настроек по умолчанию;2. Текст о том, почему вообще существование такой шпаргалки может кому-то понадобится.
Всем привет! Я Максим, бэкенд-разработчик и тимлид команды DCImanager. Я работаю в компании ISPsystem уже почти пять лет и считаю себя очень везучим человеком, ведь за эти годы я прошел путь от обычно...
Привет, Хаброжители! Хотите создавать эффективные приложения с помощью React? Тогда эта книга написана для вас. Познакомьтесь c лучшими практиками и шаблонами создания современного кода. Вам не по...
В условиях когда большая часть заявок на кредит рассматривается автоматически, мониторинг становится особенно важным. Всё ли работает в штатном режиме, как меняются ключевые показатели, какие изм...