import { Callout } from 'nextra/components' # Рефакторинг Проблема: - Компонент LoginForm стал слишком сложным, в нем много логики завязанной на формах, и всему виной useController. Решение: - Создать автономные компоненты `ControlledCheckbox` и `ControlledTextField` и использовать их в `LoginForm` ## ControlledCheckbox ### Минимально рабочая реализация Создадим файл `controlled-checkbox.tsx` и вынесем туда логику `useController` и `Checkbox`: ```tsx filename="src/components/ui/controlled/controlled-checkbox/controlled-checkbox.tsx" import { useController, UseControllerProps } from 'react-hook-form' import { Checkbox, CheckboxProps } from '@/components' export type ControlledCheckboxProps = UseControllerProps & Omit export const ControlledCheckbox = ({ name, rules, shouldUnregister, control, defaultValue, ...checkboxProps }: ControlledCheckboxProps) => { const { field: { onChange, value }, } = useController({ name, rules, shouldUnregister, control, defaultValue, }) return ( ) } ``` В UseControllerProps пока что передадим any Уберем из `LoginForm` логику `useController` и заменим на `ControlledCheckbox`: ```tsx filename="src/components/auth/login-form/login-form.tsx" showLineNumbers {12} import { ControlledCheckbox } from '@/components' // ... return (
) ``` Проп `name` отвечает за название поля в форме, а `control` за то, какой контроллер будет использоваться. Убедитесь что все работает как надо ### Типизация Проблема: Сейчас в качестве control и name можно передать что угодно, а это может привести к ошибкам которые тяжело дебажить. Теперь давайте типизируем `ControlledCheckboxProps`, для этого воспользуемся дженериками: ```tsx filename="src/components/ui/controlled/controlled-checkbox/controlled-checkbox.tsx" showLineNumbers {1,5,6,8,15} import { FieldValues, useController, UseControllerProps } from 'react-hook-form' import { Checkbox, CheckboxProps } from '@/components' export type ControlledCheckboxProps = UseControllerProps & Omit export const ControlledCheckbox = ({ name, rules, shouldUnregister, control, defaultValue, ...checkboxProps }: ControlledCheckboxProps) => { // ... } ``` Попробуем допустить ошибку в `name`: ![controlled-checkbox-typescript-working](./images/controlled-checkbox-typescript-working.png) Все работает как и ожидалось :) ## React-hook-form devtools Проблема: - Дебажить через консоль неудобно, хочется видеть что происходит в форме в реальном времени. Решение: - Использовать [react-hook-form devtools](https://www.react-hook-form.com/dev-tools/) ### Установка Установим devtools: ```bash filename="Terminal" pnpm i -D @hookform/devtools ``` ### Использование И добавим их в `LoginForm`: ```tsx filename="src/components/auth/login-form/login-form.tsx" showLineNumbers {1,7} import { DevTool } from '@hookform/devtools' // ... return (
) ``` ### Скриншоты Теперь у нас появилась кнопка, при нажатии на которую открывается панель с информацией о форме: ![react-hook-form-devtools-button](./images/rhf-devtool-button.png) ![react-hook-form-devtools-panel](./images/rhf-devtool-panel.png) Эта панель будет доступна только в разработке, в опубликованном проекте кнопки не будет.