Bắt đầu với Storybook trong React

Spread the love

Bạn đã bao giờ thử đặt tất cả các thành phần giao diện người dùng của mình tại một vị trí trong React chưa?

Nếu bạn chưa quen với thế giới React, thì có lẽ bạn sẽ không làm thế.

Điều đó có nghĩa là gì?

xem phản ứng-đẹp-dnd ví dụ.

Những gì bạn đã thấy trong các ví dụ được gọi là những câu chuyện. Và công cụ được sử dụng để tạo ra những câu chuyện được gọi là Storybook.

Bây giờ, bạn đã hiểu những gì chúng ta sẽ nói trong bài viết này. Không quảng cáo, hãy cùng khám phá.

Truyện kể là gì?

Storybook là môi trường phát triển biệt lập với giao diện người dùng cung cấp sân chơi cho các thành phần của bạn. Chúng tôi có thể chơi với các thành phần của mình theo nhiều cách khác nhau mà không cần chạy ứng dụng chính của mình. Chúng tôi có thể chạy cuốn truyện trong cổng của nó với thiết lập.

Nó không giới hạn ở React. Chúng ta có thể sử dụng storybook với hầu hết các frontend framework như Vue, Angular, Mithril, Marko, Svelte, v.v.,

Các bạn có thể tham khảo thêm về cuốn truyện nơi đây.

một câu chuyện là gì?

Một câu chuyện xác định trạng thái kết xuất của thành phần của bạn. Nếu chúng ta lấy một thành phần chung, chúng ta có thể sử dụng nó theo nhiều cách khác nhau với các đạo cụ. Chúng ta có thể viết một câu chuyện cho mỗi trạng thái đó.

Giả sử chúng ta có một thành phần Nút.

Một nút có thể tồn tại ở các trạng thái khác nhau như vô hiệu hóa, đang tải, chính, phụ, nhỏ, lớn, trung bình, v.v.. Nếu chúng ta liệt kê tất cả các trạng thái thì sẽ rất khó để tiếp tục trong phần hướng dẫn. Tôi nghĩ rằng bạn hiểu nó. Bạn sẽ nhận được nhiều hơn khi bắt đầu làm việc với cuốn truyện.

Bạn có thể xem các câu chuyện của nút trong các trường hợp khác nhau (Lớn, Trung bình, Nhỏ).

Thiết lập Storybook trong một dự án

Chúng tôi sẽ thiết lập một cuốn truyện trong một dự án phản ứng.

Đi nào.

  • Tạo một dự án phản ứng bằng lệnh sau. Bạn có thể đặt tên bất cứ điều gì bạn thích.
npx create-react-app storybook-demo
  • Bây giờ, hãy cài đặt cuốn truyện trong dự án của bạn bằng lệnh sau.
npx sb init

Chúng tôi đã hoàn thành việc thiết lập cho cuốn truyện.

Truyện cung cấp một máy chủ riêng cho chúng ta.

Làm thế nào để bắt đầu nó?

Cuốn truyện tự động thêm một lệnh trong tệp kịch bản của chúng tôi. Bạn có thể kiểm tra nó trong tệp pack.json bên trong phần tập lệnh. Hiện tại, hãy chạy lệnh sau để khởi động máy chủ truyện.

npm run storybook

Storybook sẽ bắt đầu một máy chủ mới với cổng được cung cấp trong phần tập lệnh của tệp pack.json. Nó sẽ tự động mở truyện trong trình duyệt mặc định của chúng tôi (giống như máy chủ phản ứng).

Bạn sẽ thấy các câu chuyện khác nhau trong đó theo mặc định. Bạn có thể loại bỏ chúng nếu không muốn hoặc giữ lại để tham khảo. Như đã trình bày ở phần trước, một nút có thể có nhiều trạng thái, bạn có thể xem trong truyện (không đề cập hết các trạng thái). Chúng ta sẽ viết một tập hợp lớn các câu chuyện cho nút trong phần cuối cùng của hướng dẫn này.

Khám phá các phần khác nhau của cuốn truyện và làm quen với các phần khác nhau. Chúng tôi sẽ đề cập đến một vài trong số chúng trong hướng dẫn.

Hãy viết câu chuyện đầu tiên của chúng ta.

truyện thử nghiệm

Chúng tôi đã thấy cuốn truyện đang chạy và một số ví dụ trong đó.

  • Tạo một thư mục có tên Nút bên trong thư mục src.
  • Tạo các tệp có tên Button.jsx, Button.css và constants.js
  • Đặt mã tương ứng từ các đoạn dưới đây trong các tập tin.
  Cách tắt đa nhiệm trên iPad

Nút.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 };

Nút.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;
}

hằng.js

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

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

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

Mã đó là gì?

Chúng tôi đã viết một thành phần chung cho Nút có thể được sử dụng theo nhiều cách khác nhau. Bây giờ, chúng ta có một thành phần có thể có các trạng thái khác nhau.

Hãy viết câu chuyện đầu tiên của chúng tôi bằng cách làm theo các bước dưới đây.

  • Tạo một tệp có tên Button.stories.jsx
  • Nhập React và thành phần Nút của chúng tôi vào tệp.
  • Bây giờ, hãy xác định tiêu đề hoặc đường dẫn cho các câu chuyện thành phần của chúng ta. Chúng tôi sẽ xác định nó bằng mã sau đây.
export default {
   title: ‘common/Button’,
}

Đoạn mã trên sẽ đặt tất cả các câu chuyện trong tệp hiện tại bên trong thư mục chung/Nút/.

  • Xuất một nút với các đạo cụ bắt buộc như sau.
export const defaultButton = () => (
    <Button text=”Default Button” onClick={() => {}} />
);

Chúng tôi đã hoàn thành câu chuyện đầu tiên của mình. Chạy cuốn truyện bằng lệnh sau và xem đầu ra.

npm run storybook

Cuối cùng, chúng tôi sẽ viết nhiều câu chuyện hơn, đừng lo lắng.

Nó hữu ích như thế nào trong việc phát triển Frontend?

Ưu điểm chính của việc sử dụng một cuốn truyện là gì?

Giả sử chúng ta đang làm việc trong một nhóm gồm 10 thành viên. Và chúng ta cần kiểm tra các thành phần phổ biến mà mọi người đã viết cho dự án đang làm việc hiện tại.

Làm thế nào chúng ta có thể làm điều đó?

Chúng ta phải đi đến từng thành phần chung để kiểm tra chúng. Tuy nhiên, nó tốn thời gian và không phải là cách ưa thích đối với chúng tôi. Đây là cuốn truyện khách mới của chúng tôi.

Làm thế nào để sử dụng nó để khắc phục vấn đề của chúng tôi?

Chúng ta có thể viết các câu chuyện cho các thành phần phổ biến (bất kỳ thành phần giao diện người dùng nào) bằng cách sử dụng sổ truyện. Và bất cứ khi nào đồng đội của bạn muốn kiểm tra các thành phần chung của người khác, thì họ chỉ cần chạy máy chủ truyện và sẽ thấy tất cả các thành phần UI ở đó như chúng ta đã thấy ở trên.

Chúng ta có thể làm được nhiều hơn với các thành phần được kết xuất trong cuốn truyện. Storybook có một khái niệm gọi là Addons mang lại siêu năng lực cho các câu chuyện của chúng tôi.

Giả sử chúng ta phải kiểm tra khả năng phản hồi của các thành phần UI trong chính cuốn truyện, chúng ta có thể sử dụng một addon có tên là Viewport trong cuốn truyện. Chúng ta sẽ tìm hiểu thêm về các addon trong các phần tiếp theo.

Làm việc với Storybook

Trong phần này, chúng tôi sẽ viết các câu chuyện khác nhau xác định các trạng thái khác nhau của Nút thành phần chung của chúng tôi.

Viết truyện không quá khó. Một câu chuyện xác định trạng thái của một thành phần. Nếu bạn nhìn thấy các props của một component, thì bạn sẽ dễ dàng hiểu được các trường hợp sử dụng khác nhau của component đó.

Hãy viết một số câu chuyện bằng cách đưa ra các đạo cụ tùy chọn.

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

Ba câu chuyện trên xác định các trường hợp sử dụng khác nhau của Nút thành phần của chúng tôi. Bây giờ, đến lượt bạn thêm một số trường hợp câu chuyện khác cho thành phần chung của chúng ta. Hãy thử thêm disableSamllRectangularButton, DangyButton, SuccessDisabledButton, v.v.,

  18 ứng dụng đo lường tốt nhất

Tôi sẽ không cung cấp mã cho các trường hợp trên. Bạn phải viết nó một mình để hiểu nó. Bạn có thể xem mã câu chuyện hoàn chỉnh mà chúng tôi đã viết cho đến bây giờ.

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

Bây giờ, bạn đã hoàn toàn nắm bắt được cách viết truyện cho một thành phần.

Hãy chuyển sang phần tiếp theo, nơi chúng ta sẽ tìm hiểu về addon và cách chúng thúc đẩy câu chuyện của chúng ta.

Addons truyện

Chúng tôi sẽ có sẵn nhiều addon theo mặc định. Trong phần này, chúng ta sẽ khám phá các addon hữu ích nhất cho sự phát triển của chúng ta.

Hãy thúc đẩy các câu chuyện về Nút của chúng tôi.

điều khiển

Các điều khiển thêm một tính năng để cung cấp các đạo cụ tùy chỉnh cho thành phần trong chính cuốn truyện. Đối với thành phần Nút của chúng tôi, chúng tôi có thể thêm các điều khiển để thay đổi các đạo cụ khác nhau trong sách truyện.

Giả sử chúng ta phải tìm ra màu tốt nhất cho màu nền của Nút. Sẽ rất mất thời gian nếu chúng ta chạy thử để kiểm tra màu nền bằng cách cho từng cái một vào linh kiện. Thay vào đó, chúng ta có thể thêm một điều khiển cho phép chúng ta chọn màu khác trong cuốn truyện. Chúng ta có thể thử màu nền trong chính cuốn truyện.

Hãy xem cách thêm các điều khiển vào các câu chuyện về Nút của chúng tôi.

Đầu tiên, chúng ta phải xác định tất cả các đạo cụ bên dưới tiêu đề như sau.

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

Tiếp theo, tách các đạo cụ khỏi thành phần và cung cấp cho chúng các đối số như sau.

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

Bạn có thể thấy các điều khiển ở dưới cùng của cửa sổ xem trước thành phần.

Bạn có thể thấy tab điều khiển ở cuối cửa sổ xem trước thành phần. Chơi xung quanh nó.

Cập nhật tất cả các truyện như trên. Điều này giống như biết cú pháp của các phần bổ sung trong truyện. Trong argTypes, chúng tôi đã sử dụng các loại điều khiển khác nhau. Bạn có thể tìm thấy tất cả các điều khiển có trong cuốn truyện nơi đây.

Các câu chuyện về nút được cập nhật sẽ trông như sau.

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

hành động

Hành động là các sự kiện trong JavaScript. Chúng ta có thể nhấp vào một nút là một sự kiện trong JavaScript. Chúng tôi có thể thực hiện một số hành động khi nhấp vào nút bằng cách sử dụng addon hành động.

  Easy Anti-Cheat là gì và làm thế nào để cài đặt nó?

Với các hành động, chúng tôi có thể kiểm tra xem các sự kiện có hoạt động bình thường hay không. Không thể nhấp vào nút đã tắt và nút đã bật phải có thể nhấp được. Chúng tôi có thể đảm bảo nó bằng cách sử dụng các hành động.

Hãy xem cách thêm hành động vào nút bấm.

Chúng tôi đã cung cấp chức năng ẩn danh cho đạo cụ onClick trước đây. Bây giờ, chúng ta phải cập nhật nó.

  • Nhập hành động từ addon sách truyện bằng cách sử dụng câu lệnh sau.
import { action } from "@storybook/addon-actions";
  • Thay thế tất cả () => {} bằng câu lệnh sau.
action("Button is clicked!")

Bây giờ, đi đến cuốn truyện và nhấp vào một nút. Bạn sẽ thấy thông báo được in dưới tab hành động bên cạnh tab điều khiển. Thông báo sẽ không được in nếu bạn nhấp vào nút bị vô hiệu hóa vì nó bị vô hiệu hóa.

Chúng tôi có thể sử dụng hành động cho các sự kiện khác nhau như onChange, onMouseOver, onMouseOut, v.v., để đảm bảo chúng hoạt động bình thường. Hãy thử triển khai tương tự cho onChange đối với phần tử đầu vào.

Xem tài liệu cho các hành động nơi đây.

Tiểu sử

Chúng ta có thể thay đổi nền của cửa sổ xem trước bằng addon nền. Chúng tôi không phải viết bất kỳ mã nào. Chỉ cần thay đổi nó bên trong cuốn truyện. Bạn có thể xem gif bên dưới.

Chế độ xem

Chúng tôi cũng có thể kiểm tra khả năng phản hồi của các thành phần trong cuốn truyện. Xem gif bên dưới để tìm hiểu về các tùy chọn khung nhìn.

Tài liệu

Chúng tôi có thể ghi lại các thành phần của mình trong sách truyện bằng addon tài liệu. Nó hữu ích hơn khi chúng ta làm việc theo nhóm. Họ sẽ đọc thành phần và hiểu nó trực tiếp. Nó tiết kiệm rất nhiều thời gian cho các nhà phát triển.

Trong cửa sổ xem trước các thành phần của sách truyện, bạn có thể thấy Tài liệu ở trên cùng bên phải của tab Canvas. Nó sẽ chứa tất cả các tài liệu của tất cả các câu chuyện của một thành phần. Chúng tôi phải sử dụng Button.stories.mdx nếu chúng tôi muốn ghi lại thành phần bao gồm cả đánh dấu và hiển thị thành phần. Chúng tôi chỉ viết một số mã đánh dấu bổ sung bên trong nó cùng với các câu chuyện thành phần.

Chúng tôi đang viết một tài liệu cho câu chuyện của chúng tôi. Mã bao gồm đánh dấu và hiển thị thành phần. Tất cả chỉ là học cú pháp. Bạn sẽ nhận được nó cái nhìn đầu tiên.

Hãy xem mã tài liệu 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>

Tìm hiểu thêm về các thành phần tài liệu nơi đây.

Bạn có thể tìm hiểu thêm về các tiện ích bổ sung nơi đây.

Sự kết luận

Hy vọng bạn thích hướng dẫn và tìm hiểu về cuốn truyện. Và sử dụng nó một cách hiệu quả trong nhóm của bạn để làm cho công việc của bạn hiệu quả.

Mới để phản ứng? Kiểm tra các tài nguyên học tập.

Mã hóa vui vẻ 🙂

x