fix: update scripts in lesson 1

This commit is contained in:
2023-12-09 19:43:23 +01:00
parent 23a06d4a30
commit 8490f16115
2 changed files with 46 additions and 17 deletions

View File

@@ -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`:
![button-as-link-error.png](./images/button-as-link-error.png)
Типизация работает правильно, потому что в первом случае мы отрисовываем тэг `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).
## Коммитим изменения

View File

@@ -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)