Първи стъпки с Storybook в React

Опитвали ли сте някога да поставите всичките си UI компоненти на място в React?

Ако сте нов в света на React, вероятно няма да го направите.

Какво има предвид това?

Вижте реагира-красиво-dnd примери.

Това, което сте видели в примерите, се нарича истории. И инструментът, който се използва за създаване на истории, се нарича Storybook.

Сега разбрахте за какво ще говорим в тази статия. Без приказки, нека изследваме.

Какво е книга с разкази?

Storybook е среда за разработка, изолирана от потребителския интерфейс, която предоставя площадка за вашите компоненти. Можем да играем с нашите компоненти по различни начини, без да стартираме нашето основно приложение. Можем да стартираме книгата с разкази в нейния порт с настройката.

Не се ограничава до React. Можем да използваме книга с разкази с повечето фронтенд рамки като Vue, Angular, Mithril, Marko, Svelte и др.,

Можете да намерите повече за книгата с разкази тук.

Какво е история?

Историята определя изобразеното състояние на вашия компонент. Ако вземем общ компонент, можем да го използваме по различни начини с подпори. Можем да напишем история за всяко от тези състояния.

Да кажем, че имаме компонент Button.

Един бутон може да съществува в различни състояния като дезактивиран, зареждащ се, първичен, вторичен, малък, голям, среден и т.н., ако изброим всички състояния, тогава ще бъде много трудно да продължим напред в урока. Мисля, че го разбирате. Ще получите повече, когато започнете да работите с книгата с разкази.

Можете да видите историите на бутона в различни случаи (Голям, Среден, Малък).

Настройване на книга с разкази в проект

Ще настроим книга с разкази в проект на React.

Да тръгваме.

  • Създайте проект за реакция със следната команда. Можете да назовете каквото искате.
npx create-react-app storybook-demo
  • Сега инсталирайте книгата с разкази във вашия проект със следната команда.
npx sb init

Завършихме настройката за книгата с разкази.

Книгата с разкази предоставя отделен сървър за нас.

Как да го стартирам?

Книгата с разкази автоматично добавя команда в нашия скриптов файл. Можете да го проверите във файла package.json в секцията за скриптове. За момента изпълнете следната команда, за да стартирате сървъра на книгата с разкази.

npm run storybook

Storybook ще стартира нов сървър с порт, даден в секцията за скриптове на файла package.json. Той автоматично ще отвори книгата с разкази в нашия браузър по подразбиране (същия като сървъра за реакция).

По подразбиране в него ще виждате различни истории. Можете да ги премахнете, ако не искате, или да ги запазите за справка. Както обсъдихме в предишния раздел, един бутон може да има множество състояния, можете да ги видите в книгата с разкази (не са споменати всички състояния). Ще напишем голям набор от истории за бутона в последния раздел на този урок.

Разгледайте различни раздели на книгата с разкази и се запознайте с различните раздели. Ще разгледаме няколко от тях в урока.

Нека напишем нашата първа история.

Тестване на книга с разкази

Видяхме как работи книгата с разкази и някои примери в нея.

  • Създайте папка, наречена Button, в папката src.
  • Създайте файлове, наречени Button.jsx, Button.css и constants.js
  • Поставете съответния код от фрагментите по-долу във файловете.

Button.jsx

import React, { Component } from "react";
import PropTypes from "prop-types";

import "./Button.css";

import { buttonTypes, buttonVariants, buttonSizes } from "./constants";

class Button extends Component {
    static defaultProps = {
        isDisabled: false,
        type: "filled",
        variant: "oval",
        size: "medium",
        backgroundColor: "#1ea7fd",
        textColor: "#ffffff",
    };

    static buttonTypes = buttonTypes;
    static buttonVariants = buttonVariants;
    static buttonSizes = buttonSizes;

    renderButton = () => {
        const {
            text,
            isDisabled,
            type,
            variant,
            size,
            backgroundColor,
            textColor,
            onClick,
        } = this.props;
        return (
            <button
                onClick={onClick}
                className={`default ${variant} ${size} ${
                    isDisabled ? "disabled" : ""
                }`}
                style={
                    type === buttonTypes.outline
                        ? {
                              border: `1px solid ${backgroundColor}`,
                              color: "#000000",
                              backgroundColor: "transparent",
                          }
                        : {
                              backgroundColor: `${backgroundColor}`,
                              border: `1px solid ${backgroundColor}`,
                              color: textColor,
                          }
                }
                disabled={isDisabled}
            >
                {text}
            </button>
        );
    };

    render() {
        return this.renderButton();
    }
}

Button.propTypes = {
    text: PropTypes.string,
    isDisabled: PropTypes.bool,
    type: PropTypes.oneOf([buttonTypes.outline, buttonTypes.filled]),
    variant: PropTypes.oneOf([buttonVariants.oval, buttonVariants.rectangular]),
    size: PropTypes.oneOf([
        buttonSizes.small,
        buttonSizes.medium,
        buttonSizes.large,
    ]),
    backgroundColor: PropTypes.string,
    textColor: PropTypes.string,
    onClick: PropTypes.func,
};

export { Button };

Button.css

.default {
    border: none;
    cursor: pointer;
    background-color: transparent;
}

.default:focus {
    outline: none;
}

.disabled {
    opacity: 0.75; 
    cursor: not-allowed;
}
.small {
    font-size: 12px;
    padding: 4px 8px;
}

.medium {
    font-size: 14px;
    padding: 8px 12px;
}

.large {
    font-size: 16px;
    padding: 12px 16px;
}

.oval {
    border-radius: 4px;
}

.rectangular {
    border-radius: 0;
}

константи.js

export const buttonTypes = {
    outline: "outline",
    filled: "filled",
};

export const buttonVariants = {
    oval: "oval",
    rectangular: "rectangular",
};

export const buttonSizes = {
    small: "small",
    medium: "medium",
    large: "large",
};

Какъв е този код?

  Стартирайте вашата интернет радиостанция [7 Broadcast and Hosting Services]

Написахме общ компонент за Button, който може да се използва по различни начини. Сега имаме компонент, който може да има различни състояния.

Нека напишем нашата първа история, като следваме стъпките по-долу.

  • Създайте файл с име Button.stories.jsx
  • Импортирайте React и нашия компонент Button във файла.
  • Сега дефинирайте заглавие или път към историите на нашите компоненти. Ще го дефинираме с помощта на следния код.
export default {
   title: ‘common/Button’,
}

Горният код ще постави всички истории, които са в текущия файл, в директорията common/Button/.

  • Експортирайте бутон със задължителни подпори, както следва.
export const defaultButton = () => (
    <Button text=”Default Button” onClick={() => {}} />
);

Завършихме първата си история. Стартирайте книгата с разкази със следната команда и вижте резултата.

npm run storybook

Ще напишем още истории, накрая, не се притеснявайте.

Как е полезно при разработката на Frontend?

Какво е основното предимство на използването на книга с разкази?

Да речем, че работим в екип от 10 члена. И трябва да проверим общите компоненти, които всеки е написал за текущия работен проект.

Как можем да направим това?

Трябва да отидем до всеки общ компонент, за да ги проверим. Но това отнема много време и не е предпочитан начин за нас. Ето и новата ни книга с разкази за гости.

Как да го използваме, за да преодолеем проблема си?

Можем да пишем истории за общите компоненти (всеки UI компоненти), използвайки книга с разкази. И всеки път, когато вашият съотборник иска да провери общите компоненти на другите, тогава те просто стартират сървъра на книгата с разкази и ще видят всички компоненти на потребителския интерфейс там, както видяхме по-горе.

Можем да направим много повече с изобразените компоненти в книгата с разкази. Storybook има концепция, наречена Addons, която дава суперсили на нашите истории.

Да кажем, че трябва да проверим отзивчивостта на компонентите на потребителския интерфейс в самата книга с разкази, можем да използваме добавка, наречена Viewport в книгата с разкази. Ще научим повече за добавките в следващите раздели.

Работа с книга с разкази

В този раздел ще напишем различни истории, дефиниращи различни състояния на нашия общ компонент Button.

Писането на истории не е толкова трудно. Историята определя състоянието на компонент. Ако видите реквизитите на компонент, тогава лесно ще разберете различните случаи на употреба на компонента.

Нека напишем няколко истории, като предоставим незадължителен реквизит.

export const largeButton = () => (
    <Button text="Large Button" onClick={() => {}} size="large" />
);
export const outlineSmallButton = () => (
    <Button
        text="Outline Small Button"
        onClick={() => {}}
        size="small"
        type="outline"
    />
);
export const rectangularLargeButton = () => (
    <Button
        text="Rectangular Large Button"
        onClick={() => {}}
        size="large"
        variant="rectangular"
    />
);


export const disabledButton = () => (
    <Button text="Disabled Button" onClick={() => {}} isDisabled={true} />
);


export const warningButton = () => (
    <Button
        text="Warning Button"
        onClick={() => {}}
        backgroundColor="orange"
    />
);

Горните три истории дефинират различни случаи на използване на нашия компонент Button. Сега е ваш ред да добавите някои други случаи на истории за нашия общ компонент. Опитайте се да добавите disabledSamllRectangularButton, dangerButton, successDisabledButton и т.н.,

  Как безопасно да почистите гадните си игрови контролери

Няма да предоставя код за горните случаи. Трябва да го напишеш сам, за да го разбереш. Можете да видите пълния код на историите, който сме написали до момента.

import React from "react";

import { Button } from "./Button";

export default {
    title: "src/common/Button",
};

export const defaultButton = () => (
    <Button text="Default Button" onClick={() => {}} />
);

export const largeButton = () => (
    <Button text="Large Button" onClick={() => {}} size="large" />
);

export const outlineSmallButton = () => (
    <Button
        text="Outline Small Button"
        onClick={() => {}}
        size="small"
        type="outline"
    />
);

export const rectangularLargeButton = () => (
    <Button
        text="Rectangular Large Button"
        onClick={() => {}}
        size="large"
        variant="rectangular"
    />
);

export const disabledButton = () => (
    <Button text="Disabled Button" onClick={() => {}} isDisabled={true} />
);

export const warningButton = () => (
    <Button
        text="Disabled Button"
        onClick={() => {}}
        backgroundColor="orange"
    />
);

Сега имате пълен контрол върху писането на истории за компонент.

Нека преминем към следващия раздел, където ще научим за добавките и как те подобряват нашите истории.

Добавки към книга с разкази

По подразбиране ще имаме налични множество добавки. В раздела ще разгледаме най-полезните добавки за нашето развитие.

Нека подобрим нашите истории за бутони.

Контроли

Контролите добавят функция за предоставяне на персонализирани реквизити на компонента в самата книга с разкази. За нашия компонент Button можем да добавим контроли за промяна на различните подпори в книгата с разкази.

Да кажем, че трябва да намерим най-добрия цвят за фоновия цвят на бутона. Ще отнеме много време, ако го тестваме, за да проверим цвета на фона, като даваме един по един на компонента. Вместо това можем да добавим контрола, която ни позволява да избираме различния цвят в книгата с разкази. Можем да тестваме цвета на фона в самата книга с разкази.

Нека да видим как да добавим контроли към нашите истории за бутони.

Първо, трябва да дефинираме всички подпори под заглавието, както следва.

export default {
    title: "src/common/Button",
    argTypes: {
        text: { control: "text" },
        backgroundColor: { control: "color" },
        isDisabled: { control: "boolean" },
        size: {
            control: { type: "select", options: ["small", "medium", "large"] },
        },
        type: {
            control: { type: "select", options: ["filled", "outline"] },
        },
        variant: {
            control: { type: "select", options: ["oval", "rectangular"] },
        },
    },
};

След това отделете реквизитите от компонента и им дайте като аргументи, както следва.

export const outlineSmallButton = (args) => (
    <Button {...args} onClick={() => {}} />
);
outlineSmallButton.args = {
    text: "Outline Small Button",
    size: "small",
    type: "outline",
};

Можете да видите контролите в долната част на прозореца за преглед на компонента.

Можете да видите раздела за контроли в долната част на прозореца за визуализация на компонента. Играйте около него.

Актуализирайте всички истории, както по-горе. Всичко това прилича повече на познаване на синтаксиса на добавките към книгата с разкази. В argTypes сме използвали различни типове контроли. Можете да намерите всички контроли, които присъстват в книгата с разкази тук.

Актуализираните истории за бутони ще изглеждат по следния начин.

import React from "react";

import { Button } from "./Button";

export default {
    title: "src/common/Button",
    argTypes: {
        text: { control: "text" },
        backgroundColor: { control: "color" },
        isDisabled: { control: "boolean" },
        size: {
            control: { type: "select", options: ["small", "medium", "large"] },
        },
        type: {
            control: { type: "select", options: ["filled", "outline"] },
        },
        variant: {
            control: { type: "select", options: ["oval", "rectangular"] },
        },
    },
};

export const defaultButton = (args) => <Button {...args} onClick={() => {}} />;
defaultButton.args = {
    text: "Default Button",
};

export const largeButton = (args) => (
    <Button {...args} onClick={() => {}} size="large" />
);
largeButton.args = {
    text: "Large Button",
};

export const outlineSmallButton = (args) => (
    <Button {...args} onClick={() => {}} />
);
outlineSmallButton.args = {
    text: "Outline Small Button",
    size: "small",
    type: "outline",
};

export const rectangularLargeButton = (args) => (
    <Button {...args} onClick={() => {}} />
);
rectangularLargeButton.args = {
    text: "Rectangular Large Button",
    size: "large",
    variant: "rectangular",
};

export const disabledButton = (args) => <Button {...args} onClick={() => {}} />;
disabledButton.args = {
    text: "Disabled Button",
    isDisabled: true,
};

export const warningButton = (args) => <Button {...args} onClick={() => {}} />;
warningButton.args = {
    text: "Warning Button",
    backgroundColor: "orange",
};

Действия

Действията са събития в JavaScript. Можем да щракнете върху бутон, който е събитие в JavaScript. Можем да извършим някои действия при натискане на бутон, като използваме добавката за действия.

  Как да добавите събития от Google Календар към Google Maps

С действия можем да проверим дали събитията работят правилно или не. Не може да се щракне върху деактивирания бутон, а върху активирания трябва да може да се щракне. Можем да го гарантираме чрез действията.

Нека видим как да добавим действие към щракването върху бутона.

По-рано сме дали анонимна функция на onClick props. Сега трябва да го актуализираме.

  • Импортирайте действието от добавката на книгата с разкази, като използвате следния оператор.
import { action } from "@storybook/addon-actions";
  • Заменете всички () => {} със следния израз.
action("Button is clicked!")

Сега отидете на книгата с разкази и щракнете върху бутон. Ще видите съобщението, отпечатано под раздела за действия, който е до раздела за контроли. Съобщението няма да бъде отпечатано, ако щракнете върху деактивирания бутон, тъй като той е деактивиран.

Можем да използваме действието за различни събития като onChange, onMouseOver, onMouseOut и др., за да сме сигурни, че работят правилно. Опитайте да приложите същото за onChange за входен елемент.

Вижте документацията за действия тук.

Заден план

Можем да променим фона на прозореца за визуализация с помощта на добавката за фон. Не е нужно да пишем никакъв код. Просто го променете в книгата с разкази. Можете да видите gif-а по-долу.

Viewport

Можем също така да тестваме отзивчивостта на нашите компоненти в книгата с разкази. Вижте GIF-а по-долу, за да научите за опциите на прозореца за изглед.

Документи

Можем да документираме нашите компоненти в книгата с разкази, като използваме добавката за документи. По-полезно е, когато работим в екип. Те ще прочетат компонента и ще го разберат директно. Това спестява много време на разработчиците.

В прозореца за визуализация на компонентите на книгите с разкази можете да видите Документи горе вдясно до раздела Платно. Той ще съдържа всички документи на всички истории на компонент. Трябва да използваме Button.stories.mdx, ако искаме да документираме за компонента, който включва както markdown, така и изобразяване на компонент. Ние просто пишем допълнителен код за маркиране вътре в него заедно с историите на компонентите.

Ние пишем документ за нашите истории. Кодът включва маркдаун и изобразяване на компоненти. Всичко е просто изучаване на синтаксиса. Ще го разберете от пръв поглед.

Нека да видим кода на документа Button.stories.mdx.

<!--- Button.stories.mdx -->

import {
    Meta,
    Story,
    Preview,
    ArgsTable
} from '@storybook/addon-docs/blocks';

import { Button } from './Button';

<Meta title="MDX/Button" component={Button} />

# Button Documentation

With `MDX` we can define a story for `Button` right in the middle of our
Markdown documentation.

<ArgsTable of={Button} />

export const Template = (args) => <Button {...args} />

## Default Button
We can write the documentation related to the Default Button
<Preview>
    <Story name="Default Button" args={{
        text: 'Default Button'
    }}>
    {Template.bind({})}
   </Story>
</Preview>

## Large Button
We are writing sample docs for two stories, you can write rest of them
<Preview>
    <Story name="Large Button" args={{
        text: "Large Button",
        }}>
        {Template.bind({})}
    </Story>
</Preview>

Научете повече за документиращите компоненти тук.

Можете да научите повече за добавките тук.

Заключение

Надяваме се, че урокът ви е харесал и сте научили за книгата с разкази. И го използвайте ефективно във вашия екип, за да направите работата си продуктивна.

Нов сте в React? Разгледайте тези учебни ресурси.

Приятно кодиране 🙂