Часть 2 - статически типизированные стилизованные компоненты
Если вас заинтересовала первая часть статьи, нажмите на ссылку ниже 🤓
Теперь, когда мы создали наш первый компонент, вы, вероятно, заметили, что мы не использовали ни статический машинописный текст, ни стили условных стилей компонентов с помощью свойств. Чтобы условно изменить стили компонента, мы можем воспользоваться синтаксисом строки шаблона внутри определения компонента.
// src/components/button/index.tsx import styled from "styled-components"; const StyledButton = styled.button` padding-bottom: 10px; padding-left: 20px; padding-right: 20px; padding-top: 15px; background-color: ${props => (props.active ? "red" : "green")}; &:active { outline: 0; color: #fff; top: 1px; } `; export const Button = StyledButton;
Но похоже, что с нашим кодом что-то не так. Мы не указали, какие свойства принимает наш компонент. Это вызовет красную подсветку IDE и ошибку компиляции. Чтобы исправить это, нам нужно создать интерфейс и использовать его как общий тип свойств нашего компонента.
// src/components/button/index.tsx import styled from "styled-components"; interface ButtonProps { active?: boolean; } const StyledButton = styled.button<ButtonProps>` padding-bottom: 10px; padding-left: 20px; padding-right: 20px; padding-top: 15px; background-color: ${props => (props.active ? "red" : "green")}; (...)
Ошибок нет 🎉. Чтобы передать свойства стилизованному компоненту, мы просто передаем их, как и любой другой компонент реакции.
// src/components/button/index.tsx import React from "react"; import { storiesOf } from "@storybook/react"; import {Button} from './'; storiesOf("Button", module) .add("with text", () => ( <div> <Button active={true}>Active button</Button> <Button active={false}>Not active button</Button> </div> ));
Теперь вроде все работает нормально. История показывает правильные стили для статических свойств. Давайте создадим интерактивную версию этой истории. Чтобы предоставить историям временное состояние, мы можем использовать аддон-сборник рассказов @ sambego / storybook-state.
npm i @sambego/storybook-state
Вот отрывок истории, которая меняет состояние кнопки после каждого нажатия:
// src/components/button/index.tsx import React from "react"; import { storiesOf } from "@storybook/react"; import { Button } from "./"; import { State, Store } from "@sambego/storybook-state"; const store = new Store({ active: false }); storiesOf("Button", module).add("with text", () => ( <State store={store}> {state => ( <Button active={state.active} onClick={() => { store.set({ active: !state.active }); }} > Active button </Button> )} </State> ));
Тематика
Тематизация - еще одна замечательная особенность библиотеки стилизованных компонентов. Он позволяет хранить общие значения, такие как цвета, отступы или даже функции, в глобальном объекте, который будет предоставлен всем компонентам. Он становится еще более мощным, когда мы объединяем эту функцию с хорошими качествами машинописного текста.
Чтобы добавить поддержку темы, оберните свой компонент в ThemeProvider, чтобы предоставить вашему компоненту дополнительное свойство под названием тема.
// src/components/button/button.stories.js import { ThemeProvider } from "styled-components"; ... <ThemeProvider theme={{activeColor: 'red', regularColor: 'green'}}> <Button active={state.active} onClick={() => { store.set({ active: !state.active }); }} > Active button </Button> </ThemeProvider> ...
Это дает нам возможность ссылаться на атрибуты темы в самом стилизованном компоненте.
const StyledButton = styled.button<ButtonProps>` ... background-color: ${props => (props.active ? props.theme.activeColor : props.theme.regularColor)}; ...
Свойство props темы предоставляется самими стилизованными компонентами, и нам не нужно было указывать его структуру, потому что его тип установлен на любой (что в основном полностью исключает проверку типов машинописного текста).
При работе с более крупными проектами вам, вероятно, не захочется гадать, что и что значит. Это даже пригодится, когда вы пытаетесь прочитать код своей 6-месячной давности, поверьте мне 🙈. С красивым статически типизированным кодом нет необходимости гадать, поскольку все является результатом чего-то другого. Вот почему нам не нужно НИ ОДИН в нашем коде !!! Как это сделать? Нам нужно указать машинописному тексту, какую тему мы используем. Для этого давайте определим тип нашей темы, как указано ниже. И реэкспорт в стиле «стилизованных компонентов» со статически типизированной темой.
// src/theme.ts export interface Theme { activeColor: string; regularColor: string; } // src/styled.ts import * as baseStyled from "styled-components"; import { Theme } from "./theme"; //Import our interface const { default: styledTyped /* Rename default export of baseStyled */, ThemeProvider } = baseStyled as baseStyled.ThemedStyledComponentsModule<Theme>; // And cast it to ThemedStyledComponentsModule<Theme> with previously specified Theme type export { ThemeProvider }; export default styledTyped;
Затем мы должны изменить стилизованный экземпляр в нашем компоненте кнопки, чтобы использовать эту повторно экспортированную строго типизированную версию стилизованных компонентов, созданных выше.
// src/components/button/index.ts import styled from "../../styled"; //Changed to our local styled interface ButtonProps { active?: boolean; } const StyledButton = styled.button<ButtonProps>` ...
Если это не убеждает вас в том, что машинописный текст - это круто, у меня есть несколько других примеров React в процессе разработки. Я уверен, что это изменит способ написания наших приложений и поможет избежать множества ошибок без необходимости проверять код вручную.
В следующем рассказе я расскажу о тестировании, сборке и публикации вашего пакета в репозитории npm. Мы также поэкспериментируем с другими дополнениями для сборников рассказов 🤩