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. Создать отдельный компонент для каждого варианта кнопки 2. Создать отдельный компонент для каждого варианта кнопки
Мы отдадим предпочтение **первому варианту**, так как он более гибкий и позволит нам легко добавлять новые варианты кнопок в будущем. Мы отдадим предпочтение **первому варианту**, так как он более гибкий и позволит нам легко добавлять
новые варианты кнопок в будущем.
### Props ### Props
@@ -57,7 +59,8 @@ export type ButtonProps = {
} & ComponentPropsWithoutRef<'button'> } & ComponentPropsWithoutRef<'button'>
``` ```
`ComponentPropsWithoutRef<'button'>` - это пропсы, которые принимает стандартный html-тег button, мы их расширяем своими пропсами. `ComponentPropsWithoutRef<'button'>` - это пропсы, которые принимает стандартный html-тег button, мы
их расширяем своими пропсами.
### Реализация ### Реализация
@@ -66,9 +69,12 @@ export type ButtonProps = {
```tsx filename="button.tsx" ```tsx filename="button.tsx"
import s from './button.module.scss' 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 ( 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_: Для проверки добавим стили в _button.module.scss_:
```scss filename="button.module.scss" ```scss filename="button.module.scss"
.button {
all: unset;
cursor: pointer;
&:focus-visible {
outline: 2px solid var(--color-info-500);
}
}
.primary { .primary {
background-color: red; background-color: red;
} }
@@ -175,8 +190,8 @@ export const FullWidth: Story = {
### Теория и реализация ### Теория и реализация
Дизайнеры могут внезапно решить, что кнопка должна выглядеть как ссылка, а ссылка как кнопка, Дизайнеры могут внезапно решить, что кнопка должна выглядеть как ссылка, а ссылка как кнопка, но при
но при этом мы должны рендерить правильные тэги в DOM, для удобства пользователей. Как быть в таком случае? этом мы должны рендерить правильные тэги в DOM, для удобства пользователей. Как быть в таком случае?
Для этого нам нужно будет передать нужный тег через пропс: Для этого нам нужно будет передать нужный тег через пропс:
```tsx filename="button.tsx" showLineNumbers {6,15,19} /Component/4 ```tsx filename="button.tsx" showLineNumbers {6,15,19} /Component/4
@@ -198,7 +213,10 @@ export const Button = ({
...rest ...rest
}: ButtonProps) => { }: ButtonProps) => {
return ( 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 параметр в наш компонент и в пропсы: Добавим 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) ![button-as-link-error.png](./images/button-as-link-error.png)
Типизация работает правильно, потому что в первом случае мы отрисовываем тэг `a`, у которого есть проп `href`, а во втором случае мы отрисовываем тэг `button`, у которого его нет, поэтому мы и видим ошибку. Типизация работает правильно, потому что в первом случае мы отрисовываем тэг `a`, у которого есть
проп `href`, а во втором случае мы отрисовываем тэг `button`, у которого его нет, поэтому мы и видим
ошибку.
<Callout type={'default'}> <Callout type={'default'}>
Обратите внимание, что типизацию мы тестировали в App.tsx, а не в stories, потому что storybook Обратите внимание, что типизацию мы тестировали в App.tsx, а не в stories, потому что storybook
все еще иногда ошибается с TypeScript. все еще иногда ошибается с TypeScript.
</Callout> </Callout>
Все работает как надо, но нужно поправить еще один маленький нюанс: Все работает как надо, но нужно поправить еще один маленький нюанс: Из-за того, что мы заранее не
Из-за того, что мы заранее не знаем какие пропсы будут у компонента, мы указали className как параметр нашей кнопки (расширяя стандартные пропсы), чтобы не потерять его типизацию: знаем какие пропсы будут у компонента, мы указали className как параметр нашей кнопки (расширяя
стандартные пропсы), чтобы не потерять его типизацию:
```tsx filename="button.tsx" showLineNumbers {9} ```tsx filename="button.tsx" showLineNumbers {9}
import { ComponentPropsWithoutRef, ElementType } from 'react' 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} ```tsx filename="button.tsx" showLineNumbers {13}
import { ComponentPropsWithoutRef, ElementType } from 'react' 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 - [ ] Card
- [ ] Checkbox - [ ] Checkbox
- [ ] Input (TextField) - [ ] Input (TextField)
[Видео про командную работу(из полезного примерно первый час)](https://www.youtube.com/watch?v=PROlb-RaIqk&list=PLMH1EP4byJHRnHhGr4-madQs_PNRTGXft&index=5)