Pierwsze kroki ze Storybookiem w React

Czy kiedykolwiek próbowałeś umieścić wszystkie komponenty interfejsu użytkownika w jednym miejscu w React?

Jeśli jesteś nowy w świecie React, prawdopodobnie nie.

Co to znaczy?

Zobacz reaguj-pięknie-dnd przykłady.

To, co widziałeś w przykładach, nazywa się historiami. A narzędzie używane do tworzenia historii nazywa się Storybook.

Teraz zrozumiałeś, o czym będziemy rozmawiać w tym artykule. Bez ceregieli zbadajmy.

Co to jest Storybook?

Storybook to izolowane środowisko programistyczne interfejsu użytkownika, które zapewnia plac zabaw dla twoich komponentów. Możemy bawić się naszymi komponentami na różne sposoby bez uruchamiania naszej głównej aplikacji. Możemy uruchomić książeczkę w jej porcie z konfiguracją.

Nie ogranicza się do React. Storybook możemy używać z większością frameworków frontendowych, takich jak Vue, Angular, Mithril, Marko, Svelte itp.,

Możesz znaleźć więcej o księdze bajek tutaj.

Co to jest historia?

Kondygnacja definiuje stan renderowania twojego komponentu. Jeśli weźmiemy wspólny komponent, możemy go użyć na różne sposoby z rekwizytami. Dla każdego z tych stanów możemy napisać historię.

Załóżmy, że mamy komponent Button.

Przycisk może istnieć w różnych stanach, takich jak wyłączony, ładowanie, podstawowy, drugorzędny, mały, duży, średni itp. Jeśli wymienimy wszystkie stany, bardzo trudno będzie przejść do przodu w samouczku. Myślę, że to rozumiesz. Otrzymasz go więcej, gdy zaczniesz pracować z książeczką.

Możesz zobaczyć historie przycisku w różnych przypadkach (duży, średni, mały).

Konfigurowanie Storybook w projekcie

Ustawimy storybook w projekcie Reaguj.

Chodźmy.

  • Utwórz projekt reakcji za pomocą następującego polecenia. Możesz nazwać to, co ci się podoba.
npx create-react-app storybook-demo
  • Teraz zainstaluj książeczkę w swoim projekcie za pomocą następującego polecenia.
npx sb init

Zakończyliśmy konfigurację książeczki.

Storybook zapewnia nam osobny serwer.

Jak to rozpocząć?

Storybook automatycznie dodaje polecenie w naszym pliku skryptu. Możesz to sprawdzić w pliku package.json w sekcji scripts. Na razie uruchom następujące polecenie, aby uruchomić serwer storybook.

npm run storybook

Storybook uruchomi nowy serwer z portem podanym w sekcji scripts pliku package.json. Automatycznie otworzy storybook w naszej domyślnej przeglądarce (tak samo jak serwer reagowania).

Domyślnie zobaczysz w nim różne historie. Możesz je usunąć, jeśli nie chcesz, lub zachować je w celach informacyjnych. Jak omówiliśmy w poprzedniej sekcji, przycisk może mieć wiele stanów, możesz je zobaczyć w podręczniku (nie wszystkie stany są wymienione). W ostatniej części tego samouczka napiszemy duży zestaw historii dla przycisku.

Przeglądaj różne sekcje książeczki i zapoznaj się z inną sekcją. W samouczku omówimy kilka z nich.

Napiszmy naszą pierwszą historię.

Testowanie książeczki

Widzieliśmy działanie książeczki i kilka przykładów w niej zawartych.

  • Utwórz folder o nazwie Button w folderze src.
  • Utwórz pliki o nazwach Button.jsx, Button.css i fixeds.js
  • Umieść odpowiedni kod z poniższych fragmentów w plikach.

Przycisk.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 };

Przycisk.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;
}

stałe.js

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

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

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

Co to za kod?

Napisaliśmy wspólny komponent dla Buttona, którego można używać na różne sposoby. Teraz mamy komponent, który może mieć różne stany.

Napiszmy naszą pierwszą historię, wykonując poniższe kroki.

  • Utwórz plik o nazwie Button.stories.jsx
  • Zaimportuj React i nasz komponent Button do pliku.
  • Teraz zdefiniuj tytuł lub ścieżkę naszych historii składowych. Zdefiniujemy to za pomocą następującego kodu.
export default {
   title: ‘common/Button’,
}

Powyższy kod umieści wszystkie historie znajdujące się w bieżącym pliku w katalogu common/Button/.

  • Wyeksportuj przycisk z obowiązkowymi rekwizytami w następujący sposób.
export const defaultButton = () => (
    <Button text=”Default Button” onClick={() => {}} />
);

Zakończyliśmy naszą pierwszą historię. Uruchom książeczkę za pomocą następującego polecenia i zobacz dane wyjściowe.

npm run storybook

W końcu napiszemy więcej historii, nie martw się.

Jak to jest przydatne w rozwoju Frontendu?

Jaka jest główna zaleta korzystania z książeczki?

Załóżmy, że pracujemy w 10-osobowym zespole. I musimy sprawdzić wspólne komponenty, które wszyscy napisali dla bieżącego projektu roboczego.

Jak możemy to zrobić?

Musimy podejść do każdego wspólnego elementu, aby je sprawdzić. Jest to jednak czasochłonne i nie jest dla nas preferowanym sposobem. Oto nasza nowa księga gości.

Jak to wykorzystać, aby przezwyciężyć nasz problem?

Możemy pisać historie dla wspólnych komponentów (dowolnych komponentów UI) za pomocą storybook. A kiedy twój kolega z zespołu chce sprawdzić wspólne komponenty innych, po prostu uruchamia serwer Storybook i widzi tam wszystkie komponenty interfejsu użytkownika, jak widzieliśmy powyżej.

Możemy zrobić o wiele więcej z wyrenderowanymi komponentami w księdze. Storybook ma koncepcję zwaną Addons, która daje supermoce naszym historiom.

Powiedzmy, że musimy sprawdzić responsywność komponentów interfejsu użytkownika w samej księdze, możemy użyć dodatku o nazwie Viewport w księdze. Dowiemy się więcej o dodatkach w nadchodzących sekcjach.

Praca z Storybookiem

W tej sekcji napiszemy różne historie definiujące różne stany naszego wspólnego komponentu Button.

Pisanie opowiadań nie jest takie trudne. Kondygnacja definiuje stan komponentu. Jeśli zobaczysz rekwizyty komponentu, łatwo zrozumiesz różne przypadki użycia komponentu.

Napiszmy kilka historii, podając opcjonalne rekwizyty.

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"
    />
);

Powyższe trzy historie definiują różne przypadki użycia naszego komponentu Button. Teraz twoja kolej, aby dodać kilka innych przypadków historii do naszego wspólnego komponentu. Spróbuj dodać „disabledSamllRectangularButton”, „niebezpieczny przycisk”, „succesDisabledButton” itp.,

Nie zamierzam podawać kodu dla powyższych przypadków. Musisz sam to napisać, żeby zrozumieć. Możesz zobaczyć pełny kod historii, który napisaliśmy do tej pory.

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"
    />
);

Teraz masz pełną kontrolę nad pisaniem historii dla komponentu.

Przejdźmy do następnej sekcji, w której dowiemy się o dodatkach i o tym, jak ulepszają nasze historie.

Dodatki do bajek

Domyślnie dostępnych będzie wiele dodatków. W tej sekcji przyjrzymy się najbardziej przydatnym dodatkom dla naszego rozwoju.

Zwiększmy nasze historie o przyciskach.

Sterownica

Kontrolki dodają funkcję dodawania niestandardowych rekwizytów do komponentu w samej księdze. Do naszego komponentu Button możemy dodać kontrolki, aby zmieniać różne rekwizyty w księdze.

Powiedzmy, że musimy znaleźć najlepszy kolor dla koloru tła przycisku. Będzie to czasochłonne, jeśli przetestujemy to, aby sprawdzić kolor tła, podając jeden po drugim komponentowi. Zamiast tego możemy dodać kontrolkę, która pozwala nam wybrać inny kolor w książeczce. Możemy przetestować kolor tła w samej książeczce.

Zobaczmy, jak dodać kontrolki do naszych historii o przyciskach.

Najpierw musimy zdefiniować wszystkie rekwizyty pod tytułem w następujący sposób.

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"] },
        },
    },
};

Następnie oddziel rekwizyty od komponentu i podaj je jako argumenty w następujący sposób.

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

Możesz zobaczyć elementy sterujące na dole okna podglądu komponentu.

Możesz zobaczyć zakładkę kontroli na dole okna podglądu komponentu. Pobaw się w to.

Zaktualizuj wszystkie historie jak powyżej. To wszystko przypomina bardziej znajomość składni dodatków do bajek. W argTypes użyliśmy różnych typów kontrolek. Możesz znaleźć wszystkie kontrolki, które są obecne w księdze tutaj.

Zaktualizowane historie przycisków będą wyglądać następująco.

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",
};

działania

Akcje to zdarzenia w JavaScript. Możemy kliknąć przycisk, który jest zdarzeniem w JavaScript. Możemy wykonać pewne akcje po kliknięciu przycisku za pomocą dodatku do akcji.

Za pomocą akcji możemy sprawdzić, czy zdarzenia działają poprawnie, czy nie. Wyłączonego przycisku nie można kliknąć, a przycisku włączonego należy kliknąć. Możemy to zapewnić za pomocą działań.

Zobaczmy, jak dodać akcję do kliknięcia przycisku.

Wcześniej nadaliśmy anonimową funkcję rekwizytom onClick. Teraz musimy go zaktualizować.

  • Zaimportuj akcję z dodatku Storybook, używając następującej instrukcji.
import { action } from "@storybook/addon-actions";
  • Zamień wszystkie () => {} na następującą instrukcję.
action("Button is clicked!")

Teraz przejdź do książeczki i kliknij przycisk. Zobaczysz komunikat wydrukowany pod zakładką działań, która znajduje się obok zakładki sterowania. Wiadomość nie zostanie wydrukowana, jeśli klikniesz przycisk wyłączenia, ponieważ jest wyłączony.

Możemy użyć akcji dla różnych zdarzeń, takich jak onChange, onMouseOver, onMouseOut itp., Aby upewnić się, że działają poprawnie. Spróbuj zaimplementować to samo dla onChange dla elementu wejściowego.

Zapoznaj się z dokumentacją działań tutaj.

Tło

Możemy zmienić tło okna podglądu za pomocą dodatku do tła. Nie musimy pisać żadnego kodu. Po prostu zmień to w księdze bajek. Możesz zobaczyć gifa poniżej.

rzutnia

Możemy również przetestować responsywność naszych komponentów w książeczce. Zobacz gif poniżej, aby dowiedzieć się o opcjach rzutni.

Dokumenty

Możemy udokumentować nasze komponenty w storybooku za pomocą dodatku docs. Jest to bardziej przydatne, gdy pracujemy w zespole. Będą czytać komponent i rozumieć go bezpośrednio. Oszczędza to dużo czasu programistom.

W oknie podglądu komponentów Storybooks możesz zobaczyć Dokumenty w prawym górnym rogu zakładki Canvas. Będzie zawierał wszystkie dokumenty wszystkich historii komponentu. Musimy użyć Button.stories.mdx, jeśli chcemy udokumentować komponent, który obejmuje zarówno przecenę, jak i renderowanie komponentu. Po prostu piszemy w nim dodatkowy kod przeceny wraz z historiami komponentów.

Piszemy dokument dla naszych historii. Kod obejmuje przecenę i renderowanie komponentów. To wszystko to tylko nauka składni. Dostaniesz to na pierwszy rzut oka.

Zobaczmy kod dokumentu 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>

Dowiedz się więcej o składnikach dokumentacji tutaj.

Możesz dowiedzieć się więcej o dodatkach tutaj.

Wniosek

Mam nadzieję, że podobał ci się samouczek i dowiedziałeś się o książeczce. I używaj go skutecznie w swoim zespole, aby Twoja praca była produktywna.

Chcesz zareagować? Sprawdź te zasoby edukacyjne.

Miłego kodowania 🙂