diff --git a/pages/lesson-2/_meta.ru.json b/pages/lesson-2/_meta.ru.json index 54d12b3..bd998a0 100644 --- a/pages/lesson-2/_meta.ru.json +++ b/pages/lesson-2/_meta.ru.json @@ -1,4 +1,5 @@ { "chapter-1": "Глава 1. React-hook-form", - "chapter-2": "Глава 2. Валидация форм" + "chapter-2": "Глава 2. Валидация форм", + "chapter-3": "Глава 3. Рефакторинг" } diff --git a/pages/lesson-2/chapter-3.en.mdx b/pages/lesson-2/chapter-3.en.mdx new file mode 100644 index 0000000..922266a --- /dev/null +++ b/pages/lesson-2/chapter-3.en.mdx @@ -0,0 +1 @@ +# Under construction diff --git a/pages/lesson-2/chapter-3.ru.mdx b/pages/lesson-2/chapter-3.ru.mdx new file mode 100644 index 0000000..c1dd3f8 --- /dev/null +++ b/pages/lesson-2/chapter-3.ru.mdx @@ -0,0 +1,170 @@ +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) + + + Эта панель будет доступна только в разработке, в опубликованном проекте кнопки не будет. + diff --git a/pages/lesson-2/images/controlled-checkbox-typescript-working.png b/pages/lesson-2/images/controlled-checkbox-typescript-working.png new file mode 100644 index 0000000..e41e025 Binary files /dev/null and b/pages/lesson-2/images/controlled-checkbox-typescript-working.png differ diff --git a/pages/lesson-2/images/rhf-devtool-button.png b/pages/lesson-2/images/rhf-devtool-button.png new file mode 100644 index 0000000..a099e61 Binary files /dev/null and b/pages/lesson-2/images/rhf-devtool-button.png differ diff --git a/pages/lesson-2/images/rhf-devtool-panel.png b/pages/lesson-2/images/rhf-devtool-panel.png new file mode 100644 index 0000000..8dcdfb3 Binary files /dev/null and b/pages/lesson-2/images/rhf-devtool-panel.png differ