mirror of
https://github.com/ershisan99/flashcards-docs.git
synced 2025-12-16 12:33:17 +00:00
lesson 2, chapter 1 /ru
This commit is contained in:
@@ -6,5 +6,6 @@
|
|||||||
"href": "https://www.figma.com/file/PwHkQjA62wyw8BSEyW4gIk/%D0%9E%D0%B1%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D0%BE-%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D1%87%D0%BA%D0%B0%D0%BC?node-id=0%3A1&mode=dev",
|
"href": "https://www.figma.com/file/PwHkQjA62wyw8BSEyW4gIk/%D0%9E%D0%B1%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D0%BE-%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D1%87%D0%BA%D0%B0%D0%BC?node-id=0%3A1&mode=dev",
|
||||||
"newWindow": true
|
"newWindow": true
|
||||||
},
|
},
|
||||||
"lesson-1": "Lesson 1: Hello World!"
|
"lesson-1": "Lesson 1: Hello World!",
|
||||||
|
"lesson-2": "Lesson 2: Forms"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,5 +6,6 @@
|
|||||||
"href": "https://www.figma.com/file/PwHkQjA62wyw8BSEyW4gIk/%D0%9E%D0%B1%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D0%BE-%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D1%87%D0%BA%D0%B0%D0%BC?node-id=0%3A1&mode=dev",
|
"href": "https://www.figma.com/file/PwHkQjA62wyw8BSEyW4gIk/%D0%9E%D0%B1%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D0%BE-%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D1%87%D0%BA%D0%B0%D0%BC?node-id=0%3A1&mode=dev",
|
||||||
"newWindow": true
|
"newWindow": true
|
||||||
},
|
},
|
||||||
"lesson-1": "Урок 1"
|
"lesson-1": "Урок 1",
|
||||||
|
"lesson-2": "Урок 2: Формы"
|
||||||
}
|
}
|
||||||
|
|||||||
7
pages/lesson-2/_meta.en.json
Normal file
7
pages/lesson-2/_meta.en.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"chapter-1": "Chapter 1",
|
||||||
|
"chapter-2": "Chapter 2",
|
||||||
|
"chapter-3": "Chapter 3",
|
||||||
|
"chapter-4": "Chapter 4",
|
||||||
|
"chapter-5": "Chapter 5"
|
||||||
|
}
|
||||||
7
pages/lesson-2/_meta.ru.json
Normal file
7
pages/lesson-2/_meta.ru.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"chapter-1": "Chapter 1",
|
||||||
|
"chapter-2": "Chapter 2",
|
||||||
|
"chapter-3": "Chapter 3",
|
||||||
|
"chapter-4": "Chapter 4",
|
||||||
|
"chapter-5": "Chapter 5"
|
||||||
|
}
|
||||||
1
pages/lesson-2/chapter-1.en.mdx
Normal file
1
pages/lesson-2/chapter-1.en.mdx
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Under construction
|
||||||
128
pages/lesson-2/chapter-1.ru.mdx
Normal file
128
pages/lesson-2/chapter-1.ru.mdx
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
# Формы
|
||||||
|
|
||||||
|
## React-hook-form
|
||||||
|
|
||||||
|
[React-hook-form](https://react-hook-form.com/) - это библиотека для управляемых форм в React. Она позволяет управлять состоянием формы и валидацией внутри формы. В отличие от других библиотек, таких как Formik, React-hook-form не использует контекст, а вместо этого полагается на нативные возможности React, такие как управляемые компоненты и хуки.
|
||||||
|
|
||||||
|
### Установка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm i react-hook-form
|
||||||
|
```
|
||||||
|
|
||||||
|
### Использование
|
||||||
|
|
||||||
|
```tsx filename="src/components/auth/login-form/login-form.tsx"
|
||||||
|
import { useForm } from 'react-hook-form'
|
||||||
|
|
||||||
|
import { Button } from '../../ui/button'
|
||||||
|
import { TextField } from '../../ui/text-field'
|
||||||
|
|
||||||
|
type FormValues = {
|
||||||
|
login: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LoginForm = () => {
|
||||||
|
const { register, handleSubmit } = useForm<FormValues>()
|
||||||
|
|
||||||
|
const onSubmit = (data: FormValues) => {
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<TextField {...register('login')} label={'login'} />
|
||||||
|
<TextField {...register('password')} label={'password'} />
|
||||||
|
<Button type="submit">Submit</Button>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx filename="src/components/auth/login-form/login-form.stories.tsx"
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
|
|
||||||
|
import { LoginForm } from './login-form'
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: 'Auth/LoginForm',
|
||||||
|
component: LoginForm,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
} satisfies Meta<typeof LoginForm>
|
||||||
|
|
||||||
|
export default meta
|
||||||
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
|
export const Primary: Story = {}
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверим:
|
||||||
|

|
||||||
|
|
||||||
|
Все работает как надо на данном этапе, но не хватает чекбокса rememberMe. Добавим его:
|
||||||
|
|
||||||
|
```tsx filename="login-form.tsx" showLineNumbers {4,11}
|
||||||
|
type FormValues = {
|
||||||
|
login: string
|
||||||
|
password: string
|
||||||
|
rememberMe: boolean
|
||||||
|
}
|
||||||
|
...
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<TextField {...register('login')} label={'login'} />
|
||||||
|
<TextField {...register('password')} label={'password'} />
|
||||||
|
<Checkbox {...register('rememberMe')} label={'remember me'} />
|
||||||
|
<Button type="submit">Submit</Button>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверяем и получаем вот такой результат:
|
||||||
|

|
||||||
|
|
||||||
|
Совсем нет то что мы ожидали. Это происходит из-за того что чекбокс из radix ui не совместим напрямую с register().
|
||||||
|
Что бы это исправить, воспользуемся хуком useController из react-hook-form:
|
||||||
|
|
||||||
|
```tsx filename="login-form.tsx" showLineNumbers {1,14,20-26,32}
|
||||||
|
import { useController, useForm } from 'react-hook-form'
|
||||||
|
|
||||||
|
import { Checkbox } from '../../ui/checkbox'
|
||||||
|
import { TextField } from '../../ui/text-field'
|
||||||
|
import { Button } from '../../ui/button'
|
||||||
|
|
||||||
|
type FormValues = {
|
||||||
|
login: string
|
||||||
|
password: string
|
||||||
|
rememberMe: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LoginForm = () => {
|
||||||
|
const { control, handleSubmit, register } = useForm<FormValues>()
|
||||||
|
|
||||||
|
const onSubmit = (data: FormValues) => {
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
field: { value, onChange },
|
||||||
|
} = useController({
|
||||||
|
name: 'rememberMe',
|
||||||
|
control,
|
||||||
|
defaultValue: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<TextField {...register('login')} label={'login'} />
|
||||||
|
<TextField {...register('password')} label={'password'} />
|
||||||
|
<Checkbox onCheckedChange={onChange} checked={value} label={'remember me'} />
|
||||||
|
<Button type="submit">Submit</Button>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Теперь все должно работать как надо!
|
||||||
1
pages/lesson-2/chapter-2.en.mdx
Normal file
1
pages/lesson-2/chapter-2.en.mdx
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Under construction
|
||||||
BIN
pages/lesson-2/images/login-form-checkbox-error.png
Normal file
BIN
pages/lesson-2/images/login-form-checkbox-error.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 220 KiB |
BIN
pages/lesson-2/images/login-form-minimal.png
Normal file
BIN
pages/lesson-2/images/login-form-minimal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 145 KiB |
1259
pnpm-lock.yaml
generated
1259
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user