Початок роботи з Storybook у React

Ви коли-небудь пробували розмістити всі свої компоненти інтерфейсу в React?

Якщо ви новачок у світі React, то, ймовірно, ні.

Що під цим мається на увазі?

Див react-beautiful-dnd приклади.

Те, що ви побачили в прикладах, називається історіями. А інструмент, який використовується для створення історій, називається Storybook.

Тепер ви зрозуміли, про що ми будемо говорити в цій статті. Без слів, давайте досліджувати.

Що таке Storybook?

Storybook — це ізольоване середовище розробки інтерфейсу користувача, яке забезпечує майданчик для ваших компонентів. Ми можемо грати з нашими компонентами різними способами, не запускаючи наш основний додаток. Ми можемо запустити книгу оповідань у її порту за допомогою налаштування.

Це не обмежується React. Ми можемо використовувати збірку оповідань з більшістю зовнішніх фреймворків, таких як Vue, Angular, Mithril, Marko, Svelte тощо,

Ви можете дізнатися більше про збірку оповідань тут.

Що таке історія?

Історія визначає відтворений стан вашого компонента. Якщо ми візьмемо загальний компонент, ми можемо використовувати його різними способами з пропами. Ми можемо написати історію для кожного з цих штатів.

Припустимо, у нас є компонент Button.

Кнопка може перебувати в різних станах, як-от вимкнено, завантаження, основний, вторинний, малий, великий, середній тощо. Якщо ми перерахуємо всі стани, то буде дуже важко просуватися вперед у посібнику. Я думаю, ти це розумієш. Ви отримаєте більше, коли почнете працювати зі збіркою оповідань.

Ви можете побачити історії кнопки в різних регістрах (великий, середній, малий).

Налаштування Storybook у проекті

Ми створимо книгу оповідань у проекті React.

Ходімо.

  • Створіть проект React за допомогою наступної команди. Ви можете називати як завгодно.
npx create-react-app storybook-demo
  • Тепер встановіть книгу оповідань у свій проект за допомогою наступної команди.
npx sb init

Ми завершили налаштування збірки оповідань.

Книга оповідань надає нам окремий сервер.

Як це почати?

Збірник оповідань автоматично додає команду в наш файл сценарію. Ви можете перевірити це у файлі package.json у розділі сценаріїв. На даний момент виконайте таку команду, щоб запустити сервер збірника оповідань.

npm run storybook

Storybook запустить новий сервер із портом, указаним у розділі сценаріїв у файлі package.json. Він автоматично відкриє книгу оповідань у нашому браузері за замовчуванням (так само, як сервер react).

За замовчуванням ви побачите в ньому різні історії. Ви можете видалити їх, якщо не хочете, або зберегти для довідки. Як ми обговорювали в попередньому розділі, кнопка може мати кілька станів, ви можете побачити їх у збірнику оповідань (згадані не всі стани). Ми збираємося написати великий набір історій для кнопки в останньому розділі цього підручника.

Досліджуйте різні розділи збірки оповідань і ознайомтеся з різними розділами. У підручнику ми розглянемо деякі з них.

Давайте напишемо нашу першу історію.

Тестування збірки оповідань

Ми бачили, як працює збірник оповідань і деякі приклади в ньому.

  • Створіть папку під назвою 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;
}

constants.js

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

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

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

Що це за код?

  Що означає «Інші Snapchatters»?

Ми написали загальний компонент для 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 осіб. І нам потрібно перевірити загальні компоненти, які всі написали для поточного робочого проекту.

Як ми можемо це зробити?

Ми повинні перевірити кожен загальний компонент. Але це забирає багато часу і не є для нас кращим способом. Ось наш новий гостьовий збірник оповідань.

Як це використати, щоб подолати нашу проблему?

Ми можемо писати історії для загальних компонентів (будь-яких компонентів інтерфейсу користувача) за допомогою збірки оповідань. І щоразу, коли ваш товариш по команді хоче перевірити загальні компоненти інших, він просто запускає сервер збірки оповідань і побачить там усі компоненти інтерфейсу користувача, як ми бачили вище.

Ми можемо зробити набагато більше з відтвореними компонентами в збірці оповідань. У збірнику оповідань є концепція під назвою Addons, яка надає нашим історіям надзвичайні можливості.

Скажімо, ми маємо перевірити реакцію компонентів інтерфейсу користувача в самому збірнику оповідань, ми можемо використати додаток під назвою Viewport у збірнику оповідань. Ми дізнаємося більше про аддони в наступних розділах.

Робота з Storybook

У цьому розділі ми напишемо різні історії, що визначають різні стани нашого спільного компонента 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 тощо,

  нова вкладка: сторінка нової вкладки Google Now із картками [Chrome]

Я не збираюся надавати код для вищевказаних випадків. Ви повинні написати це самостійно, щоб зрозуміти. Ви можете побачити повний код історій, які ми написали до цього часу.

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.

Елементи управління

Елементи керування додають функцію надання користувацьких реквізитів компоненту в самому збірнику оповідань. Для нашого компонента Button ми можемо додати елементи керування, щоб змінювати різні атрибути в збірнику оповідань.

Скажімо, нам потрібно знайти найкращий колір для кольору фону кнопки. Це займе багато часу, якщо ми протестуємо його, щоб перевірити колір фону, надаючи один за одним компоненту. Замість цього ми можемо додати елемент керування, який дозволить нам вибрати інший колір у збірнику оповідань. Ми можемо перевірити фоновий колір у самій збірці оповідань.

Давайте подивимося, як додати елементи керування до наших історій 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. Ми можемо виконувати деякі дії під час натискання кнопки за допомогою аддона дій.

  Як віддзеркалити телефон, Mac або ПК на Fire TV Stick

За допомогою дій ми можемо перевірити, чи події працюють правильно чи ні. Вимкнену кнопку не можна натиснути, а ввімкнену кнопку потрібно натиснути. Ми можемо забезпечити це за допомогою дій.

Давайте подивимося, як додати дію до натискання кнопки.

Ми надали анонімну функцію атрибутам onClick раніше. Тепер ми маємо його оновити.

  • Імпортуйте дію з надбудови збірки оповідань за допомогою наступного оператора.
import { action } from "@storybook/addon-actions";
  • Замініть усі () => {} наступним оператором.
action("Button is clicked!")

Тепер перейдіть до збірника оповідань і натисніть кнопку. Ви побачите повідомлення, надруковане під вкладкою дій поруч із вкладкою елементів керування. Повідомлення не буде надруковано, якщо ви натиснете кнопку вимкнено, оскільки вона вимкнена.

Ми можемо використовувати дію для різних подій, таких як onChange, onMouseOver, onMouseOut тощо, щоб переконатися, що вони працюють належним чином. Спробуйте реалізувати те саме для onChange для елемента введення.

Дії дивіться в документації тут.

Фон

Ми можемо змінити фон вікна попереднього перегляду за допомогою фонового аддона. Нам не потрібно писати код. Просто змініть це всередині збірки оповідань. Ви можете побачити gif нижче.

Видове вікно

Ми також можемо перевірити реакцію наших компонентів у збірнику оповідань. Щоб дізнатися про параметри вікна перегляду, перегляньте зображення нижче.

документи

Ми можемо задокументувати наші компоненти в збірнику оповідань за допомогою аддона документів. Це корисніше, коли ми працюємо в команді. Вони прочитають компонент і зрозуміють його безпосередньо. Це економить багато часу для розробників.

У вікні попереднього перегляду компонентів збірників оповідань ви можете побачити Документи вгорі праворуч на вкладці Полотно. Він міститиме всі документи всіх історій компонента. Нам потрібно використовувати Button.stories.mdx, якщо ми хочемо задокументувати компонент, який включає як розмітку, так і рендеринг компонента. Ми просто пишемо додатковий код розцінки всередині нього разом із історіями компонентів.

Ми пишемо документ для наших історій. Код включає розмітку та рендеринг компонентів. Це просто вивчення синтаксису. Ви зрозумієте це з першого погляду.

Давайте подивимося на код документа 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? Перегляньте ці навчальні ресурси.

Щасливого кодування 🙂