mirror of
https://github.com/ershisan99/flashcards-docs.git
synced 2025-12-16 20:59:26 +00:00
fix: update scripts in lesson 1
This commit is contained in:
@@ -39,10 +39,12 @@ src
|
||||
|
||||
Какие варианты реализации у нас есть?
|
||||
|
||||
1. Создать один компонент, который будет принимать все возможные пропсы и в зависимости от них будет рендериться тот или иной вариант кнопки
|
||||
1. Создать один компонент, который будет принимать все возможные пропсы и в зависимости от них будет
|
||||
рендериться тот или иной вариант кнопки
|
||||
2. Создать отдельный компонент для каждого варианта кнопки
|
||||
|
||||
Мы отдадим предпочтение **первому варианту**, так как он более гибкий и позволит нам легко добавлять новые варианты кнопок в будущем.
|
||||
Мы отдадим предпочтение **первому варианту**, так как он более гибкий и позволит нам легко добавлять
|
||||
новые варианты кнопок в будущем.
|
||||
|
||||
### Props
|
||||
|
||||
@@ -57,7 +59,8 @@ export type ButtonProps = {
|
||||
} & ComponentPropsWithoutRef<'button'>
|
||||
```
|
||||
|
||||
`ComponentPropsWithoutRef<'button'>` - это пропсы, которые принимает стандартный html-тег button, мы их расширяем своими пропсами.
|
||||
`ComponentPropsWithoutRef<'button'>` - это пропсы, которые принимает стандартный html-тег button, мы
|
||||
их расширяем своими пропсами.
|
||||
|
||||
### Реализация
|
||||
|
||||
@@ -66,9 +69,12 @@ export type ButtonProps = {
|
||||
```tsx filename="button.tsx"
|
||||
import s from './button.module.scss'
|
||||
|
||||
export const Button = ({ variant = 'primary', fullWidth, className, ...rest }: ButtonProps) => {
|
||||
export const Button = ({ className, fullWidth, variant = 'primary', ...rest }: ButtonProps) => {
|
||||
return (
|
||||
<button className={`${s[variant]} ${fullWidth ? s.fullWidth : ''} ${className}`} {...rest} />
|
||||
<button
|
||||
className={`${s.button} ${s[variant]} ${fullWidth ? s.fullWidth : ''} ${className}`}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
@@ -76,6 +82,15 @@ export const Button = ({ variant = 'primary', fullWidth, className, ...rest }: B
|
||||
Для проверки добавим стили в _button.module.scss_:
|
||||
|
||||
```scss filename="button.module.scss"
|
||||
.button {
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--color-info-500);
|
||||
}
|
||||
}
|
||||
|
||||
.primary {
|
||||
background-color: red;
|
||||
}
|
||||
@@ -175,8 +190,8 @@ export const FullWidth: Story = {
|
||||
|
||||
### Теория и реализация
|
||||
|
||||
Дизайнеры могут внезапно решить, что кнопка должна выглядеть как ссылка, а ссылка как кнопка,
|
||||
но при этом мы должны рендерить правильные тэги в DOM, для удобства пользователей. Как быть в таком случае?
|
||||
Дизайнеры могут внезапно решить, что кнопка должна выглядеть как ссылка, а ссылка как кнопка, но при
|
||||
этом мы должны рендерить правильные тэги в DOM, для удобства пользователей. Как быть в таком случае?
|
||||
Для этого нам нужно будет передать нужный тег через пропс:
|
||||
|
||||
```tsx filename="button.tsx" showLineNumbers {6,15,19} /Component/4
|
||||
@@ -198,7 +213,10 @@ export const Button = ({
|
||||
...rest
|
||||
}: ButtonProps) => {
|
||||
return (
|
||||
<Component className={`${s[variant]} ${fullWidth ? s.fullWidth : ''} ${className}`} {...rest} />
|
||||
<Component
|
||||
className={`${s.button} ${s[variant]} ${fullWidth ? s.fullWidth : ''} ${className}`}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
@@ -230,7 +248,8 @@ export const AsLink: Story = {
|
||||
|
||||
### Типизация
|
||||
|
||||
В примере выше мы использовали `as: any`, но это не очень хорошо, так как мы теряем типизацию. Давайте попробуем это исправить.
|
||||
В примере выше мы использовали `as: any`, но это не очень хорошо, так как мы теряем типизацию.
|
||||
Давайте попробуем это исправить.
|
||||
|
||||
Добавим generic параметр в наш компонент и в пропсы:
|
||||
|
||||
@@ -256,19 +275,23 @@ export const Button = <T extends ElementType = 'button'>(props: ButtonProps<T>)
|
||||
}
|
||||
```
|
||||
|
||||
Попробуем отрисовать две кнопки в App.tsx, где одна кнопка будет с тегом `button`, а другая с тегом `a`:
|
||||
Попробуем отрисовать две кнопки в App.tsx, где одна кнопка будет с тегом `button`, а другая с тегом
|
||||
`a`:
|
||||
|
||||

|
||||
|
||||
Типизация работает правильно, потому что в первом случае мы отрисовываем тэг `a`, у которого есть проп `href`, а во втором случае мы отрисовываем тэг `button`, у которого его нет, поэтому мы и видим ошибку.
|
||||
Типизация работает правильно, потому что в первом случае мы отрисовываем тэг `a`, у которого есть
|
||||
проп `href`, а во втором случае мы отрисовываем тэг `button`, у которого его нет, поэтому мы и видим
|
||||
ошибку.
|
||||
|
||||
<Callout type={'default'}>
|
||||
Обратите внимание, что типизацию мы тестировали в App.tsx, а не в stories, потому что storybook
|
||||
все еще иногда ошибается с TypeScript.
|
||||
</Callout>
|
||||
|
||||
Все работает как надо, но нужно поправить еще один маленький нюанс:
|
||||
Из-за того, что мы заранее не знаем какие пропсы будут у компонента, мы указали className как параметр нашей кнопки (расширяя стандартные пропсы), чтобы не потерять его типизацию:
|
||||
Все работает как надо, но нужно поправить еще один маленький нюанс: Из-за того, что мы заранее не
|
||||
знаем какие пропсы будут у компонента, мы указали className как параметр нашей кнопки (расширяя
|
||||
стандартные пропсы), чтобы не потерять его типизацию:
|
||||
|
||||
```tsx filename="button.tsx" showLineNumbers {9}
|
||||
import { ComponentPropsWithoutRef, ElementType } from 'react'
|
||||
@@ -291,7 +314,8 @@ export const Button = <T extends ElementType = 'button'>(props: ButtonProps<T>)
|
||||
}
|
||||
```
|
||||
|
||||
Это может привести к неожиданным коллизиям и странным ошибкам TypeScript'а, поэтому мы добавим небольшую проверку:
|
||||
Это может привести к неожиданным коллизиям и странным ошибкам TypeScript'а, поэтому мы добавим
|
||||
небольшую проверку:
|
||||
|
||||
```tsx filename="button.tsx" showLineNumbers {13}
|
||||
import { ComponentPropsWithoutRef, ElementType } from 'react'
|
||||
@@ -316,9 +340,11 @@ export const Button = <T extends ElementType = 'button'>(
|
||||
}
|
||||
```
|
||||
|
||||
С помощью Omit мы убираем из пропсов переданного компонента все пропсы, которые уже есть в наших кастомных пропсах, тем самым избегая коллизий.
|
||||
С помощью Omit мы убираем из пропсов переданного компонента все пропсы, которые уже есть в наших
|
||||
кастомных пропсах, тем самым избегая коллизий.
|
||||
|
||||
Подробнее про типизацию полиморфных компонентов можно почитать [вот тут](https://itnext.io/react-polymorphic-components-with-typescript-f7ce72ea7af2).
|
||||
Подробнее про типизацию полиморфных компонентов можно почитать
|
||||
[вот тут](https://itnext.io/react-polymorphic-components-with-typescript-f7ce72ea7af2).
|
||||
|
||||
## Коммитим изменения
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
## Компоненты
|
||||
|
||||
Создать и добавить в сторибук все компоненты которые есть в [дизайне](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?type=design&node-id=5655-1291)
|
||||
Создать и добавить в сторибук все компоненты которые есть в
|
||||
[дизайне](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?type=design&node-id=5655-1291)
|
||||
|
||||
Если не получается сделать все компоненты, то сделайте хотя бы следующие ко второму занятию:
|
||||
|
||||
@@ -11,3 +12,5 @@
|
||||
- [ ] Card
|
||||
- [ ] Checkbox
|
||||
- [ ] Input (TextField)
|
||||
|
||||
[Видео про командную работу(из полезного примерно первый час)](https://www.youtube.com/watch?v=PROlb-RaIqk&list=PLMH1EP4byJHRnHhGr4-madQs_PNRTGXft&index=5)
|
||||
|
||||
Reference in New Issue
Block a user