Интеграция с react-hook-form

React Hook Form (RHF) предоставляет эффективный способ управления формами в React с минимальным количеством ререндеров и высокой производительностью. Библиотека MUI (Material-UI) предоставляет богатый набор компонентов пользовательского интерфейса, которые легко стилизовать и настраивать. Интеграция этих двух технологий позволяет создавать современные формы с валидацией, динамическими полями и отзывчивым интерфейсом.

Регистрация компонентов MUI в React Hook Form

Для того чтобы компоненты MUI работали с RHF, важно понимать концепцию регистрации (register) и управления контролем (control). Простые элементы ввода, такие как TextField, можно регистрировать напрямую:

import { useForm } from "react-hook-form";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";

function FormExample() {
  const { register, handleSubmit } = useForm();

  const onSub mit = data => console.log(data);

  return (
    <form onSub mit={handleSubmit(onSubmit)}>
      <TextField
        label="Имя"
        {...register("name", { required: "Поле обязательно для заполнения" })}
        fullWidth
        margin="normal"
      />
      <Button type="submit" variant="contained">Отправить</Button>
    </form>
  );
}

Ключевые моменты:

  • register("name", { required: true }) связывает поле с управлением RHF.
  • TextField принимает все пропсы, необходимые для корректного отображения ошибки и значений формы.

Использование контролируемых компонентов

Некоторые компоненты MUI, такие как Select, Autocomplete, Switch или Checkbox, являются контролируемыми. Для их интеграции необходимо использовать компонент Controller из RHF:

import { useForm, Controller } from "react-hook-form";
import { Select, MenuItem, FormControl, InputLabel, Button } from "@mui/material";

function ControlledForm() {
  const { control, handleSubmit } = useForm();
  const onSub mit = data => console.log(data);

  return (
    <form onSub mit={handleSubmit(onSubmit)}>
      <FormControl fullWidth margin="normal">
        <InputLabel>Выбор</InputLabel>
        <Controller
          name="option"
          control={control}
          defaultValue=""
          rules={{ required: "Обязательное поле" }}
          render={({ field, fieldState }) => (
            <Sel ect {...field} error={!!fieldState.error}>
              <MenuItem value=""><em>Нет выбора</em></MenuItem>
              <MenuItem value="one">Один</MenuItem>
              <MenuItem value="two">Два</MenuItem>
            </Select>
          )}
        />
      </FormControl>
      <Button type="submit" variant="contained">Отправить</Button>
    </form>
  );
}

Особенности использования Controller:

  • field предоставляет стандартные методы: onChange, value, ref.
  • fieldState.error позволяет выводить сообщения об ошибках.
  • Можно задавать валидационные правила через rules.

Валидация и отображение ошибок

MUI легко интегрируется с RHF для отображения ошибок:

<TextField
  label="Email"
  {...register("email", {
    required: "Email обязателен",
    pattern: { value: /^\S+@\S+$/i, message: "Неверный формат email" }
  })}
  error={!!errors.email}
  helperText={errors.email?.message}
/>

Важные моменты:

  • error={!!errors.email} включает красную подсветку поля.
  • helperText отображает сообщение ошибки из RHF.

Для контролируемых компонентов:

<Controller
  name="subscribe"
  control={control}
  defaultValue={false}
  render={({ field, fieldState }) => (
    <FormControl error={!!fieldState.error}>
      <FormControlLabel
        control={<Switch {...field} checked={field.value} />}
        label="Подписка"
      />
      {fieldState.error && <FormHelperText>{fieldState.error.message}</FormHelperText>}
    </FormControl>
  )}
/>

Динамические формы

Использование useFieldArray из RHF позволяет создавать динамические списки полей:

import { useForm, useFieldArray, Controller } fr om "react-hook-form";
import { TextField, Button } from "@mui/material";

function DynamicForm() {
  const { control, handleSubmit } = useForm({
    defaultValues: { users: [{ name: "" }] }
  });
  const { fields, append, remove } = useFieldArray({ control, name: "users" });

  const onSub mit = data => console.log(data);

  return (
    <form onSub mit={handleSubmit(onSubmit)}>
      {fields.map((field, index) => (
        <Controller
          key={field.id}
          name={`users.${index}.name`}
          control={control}
          defaultValue={field.name}
          render={({ field }) => (
            <TextField {...field} label={`Пользователь ${index + 1}`} margin="normal" />
          )}
        />
      ))}
      <Button type="button" onCl ick={() => append({ name: "" })}>Добавить пользователя</Button>
      <Button type="submit">Отправить</Button>
    </form>
  );
}

Принципы динамических форм:

  • Каждое поле имеет уникальный key для корректного рендера.
  • append и remove позволяют добавлять и удалять элементы массива.
  • Использование Controller обеспечивает корректную синхронизацию с MUI.

Стилизация и темы

MUI предоставляет возможности кастомизации компонентов через пропсы и тему. Для интеграции с RHF это особенно важно для согласованного отображения ошибок и состояния:

import { createTheme, ThemeProvider } from "@mui/material/styles";

const theme = createTheme({
  components: {
    MuiTextField: {
      defaultProps: { variant: "outlined", fullWidth: true },
      styleOverrides: {
        root: {
          marginBottom: "16px"
        }
      }
    }
  }
});

<ThemeProvider theme={theme}>
  <FormExample />
</ThemeProvider>

Рекомендации:

  • Использовать ThemeProvider для единообразия компонентов.
  • Настраивать styleOverrides и defaultProps для всех полей формы.
  • Проверять, чтобы ошибки RHF корректно отображались при кастомных стилях.

Итоги подхода

Интеграция MUI с React Hook Form позволяет создавать:

  • Высокопроизводительные формы без лишних ререндеров.
  • Контролируемые и неконтролируемые компоненты с единым API.
  • Валидацию на лету с отображением ошибок.
  • Динамические формы и массивы полей.
  • Единообразный дизайн с помощью тем MUI.

Этот подход является стандартом для современных React-приложений, где важны удобство пользователя, скорость разработки и поддерживаемость кода.