一個 Storybook 擴充功能,用於顯示 react docgen 資訊。

在 Github 上檢視

storybook-addon-react-docgen

code style: prettier CircleCI npm npm

一個 Storybook 擴充功能,用於顯示 react docgen 資訊。此擴充功能是「info」擴充功能的 prop table 功能的直接替代品。它不是使用元件渲染,而是在擴充功能面板中渲染。也適用於 TypeScript!

存在其他執行此操作的擴充功能,但它們的運作方式與 info 擴充功能不同。這導致了複雜的組態變更。此外掛旨在讓切換過程輕鬆無痛。

Example Output

安裝

yarn add storybook-addon-react-docgen

React Docgen 整合

React Docgen 已包含在 @storybook/addon-docs 套件中。如果您正在使用 @storybook/addon-docs,則無需設定 docgen,可以跳過後續步驟

Typescript DocGen

若要在 TypeScript 專案中使用此外掛程式,您需要安裝 react-docgen-typescript-plugin 並設定 webpack 以使用它。

Javascript DocGen

若要在 JavaScript 專案中使用此外掛程式,您需要安裝 babel-plugin-react-docgen

用法

將其新增至您的 main.js 擴充功能中"

module.exports = {
  stories: ['../stories/**/*.stories.js'],
  addons: ['@storybook/addon-docs', 'storybook-addon-react-docgen']
};

然後將 withPropsTable 修飾符新增至您的 preview.js。如果需要,可以在這裡傳遞全域選項

const { addDecorator } = require('@storybook/react');
const { withPropsTable } = require('storybook-addon-react-docgen');

addDecorator(withPropsTable(options));
// or
addDecorator(withPropsTable);

您可以使用 props 參數來設定個別故事的選項

import { storiesOf } from '@storybook/react';

import Other from './Other';
import Component from './Component';

export default {
  title: 'Components/Button'
};

export const WithSomeEmoji = () => (
  <Component>
    <Other />
  </Component>
);

WithSomeEmoji.parameters: {
 props: {
   propTablesExclude: [
     Other // the actual component
   ]
 }
}

或設定整個故事的選項

import { storiesOf } from '@storybook/react';

import Other from './Other';
import Component from './Component';

export default {
  title: 'Components/Button',
  parameters: {
    props: {
      propTablesExclude: [
        Other // the actual component
      ]
    }
  }
};

export const WithSomeEmoji = () => (
  <Component>
    <Other />
  </Component>
);

組態

{
  /**
   * Components used in story
   * Displays Prop Tables with these components
   * @default []
   */
  propTables: Array<React.ComponentType>,

  /**
   * Define custom sorting order for the components specifying component names in the desired order.
   * Example:
   * propTablesSortOrder: ["MyComponent", "FooComponent", "AnotherComponent"]
   * @default []
   */
  propTablesSortOrder: string,
  /**
   * Only include prop tables for these components.
   * Accepts an array of component classes or functions
   * @default null
   */
  propTablesInclude: Array<React.ComponentType | string>,
  /**
   * Exclude Components from being shown in Prop Tables section
   * Accepts an array of component classes or functions
   * @default []
   */
  propTablesExclude: Array<React.ComponentType | string>,
  /**
   * Overrides styles of addon. The object should follow this shape:
   * https://github.com/storybooks/storybook/blob/master/addons/info/src/components/Story.js#L19.
   * This prop can also accept a function which has the default stylesheet passed as an argument
   */
  styles: Object | Function,
  /**
   * Max props to display per line in source code
   * @default 3
   */
  maxPropsIntoLine: number,
  /**
   * Displays the first 10 characters of the prop name
   * @default 3
   */
  maxPropObjectKeys: number,
  /**
   * Displays the first 10 items in the default prop array
   * @default 3
   */
  maxPropArrayLength: number,
  /**
   * Displays the first 100 characters in the default prop string
   * @default 50
   */
  maxPropStringLength: number,
  /**
   * Override the component used to render the props table
   * @default PropTable
   */
  TableComponent: React.ComponentType,
  /**
   * Will exclude any respective properties whose name is included in array.
   * Can also specify absolute propType to exclude (see example below)
   * Examples:
   * excludedPropTypes: ["message"] // propType to exclude
   * excludedPropTypes: ["MyComponent.message"] // absolute propType
   *
   * @default []
   */
  excludedPropTypes: Array<string>,
}

渲染自訂表格

TableComponent 選項可讓您定義應如何渲染 prop 表格。您的元件將以以下 props 渲染。

{
  propDefinitions: Array<{
    property: string, // The name of the prop
    propType: Object | string, // The prop type. TODO: info about what this object is...
    required: boolean, // True if the prop is required
    description: string, // The description of the prop
    defaultValue: any // The default value of the prop
  }>
}

常見問題

沒有顯示任何內容,這壞掉了!

套件為 react 實作 docgen 的方式表示在如何匯入項目和撰寫元件方面存在一些限制。

  1. 必須使用預設匯出 + 具名匯出:docgen 無法取得預設匯出的名稱,因此您還必須使用具名匯出
import * as React from "react";

interface ColorButtonProps {
  /** Buttons background color */
  color: "blue" | "green";
}

/** A button with a configurable background color. */
export const ColorButton: React.SFC<ColorButtonProps> = props => (
  <button {...props}>
);

export default ColorButton;
  1. 匯入很重要(僅限 TypeScript):您匯入 react 和使用其型別的方式必須符合一些不同的格式
// To get React.FC to work
import * as React from 'react';
export const Button: React.FC<ButtonProps> = () => {};

// Without "* as" you can only use like:
import React, { FC } from 'react';
export const Button: FC<ButtonProps> = () => {};
  1. 在故事內的使用方式很重要:此擴充功能透過尋找故事傳回的 JSX 中使用的所有元件來判斷要顯示哪些元件的 props。因此,如果您希望顯示元件的 prop-types,您必須在故事函式中傳回該元件。
import React from 'react';
import { Button } from './Button';

export default {
  title: 'Button'
};

/** WILL NOT WORK */

// Since the usage of the component is not in the JSX
// returned by the story function no props are displayed
const MyFancyExample = () => {
  const [count, setCount] = React.useState(0);

  return (
    <Button
      primary={boolean('primary', false)}
      onClick={() => setCount(count + 1)}
    >
      "hello: " {count}
    </Button>
  );
};

export const BaseStory = () => <MyFancyExample />;

/** WILL WORK */

// The JSX returned by the story uses Button, so we will
// get the props types for button.
export const BaseStory = () => {
  const [count, setCount] = React.useState(0);

  return (
    <Button
      primary={boolean('primary', false)}
      onClick={() => setCount(count + 1)}
    >
      "hello: " {count}
    </Button>
  );
};

為什麼預設 props 這麼難以正確取得?(僅限 TypeScript)

react 型別很神奇,而且您可能做得太多了。使用 React.FC 是快速增加元件複雜性的方法。一旦您使用它,您將失去 defaultProps 體驗。

使用 React.FC

interface CardProps {
  size?: 'small' | 'large';
}

// The type of size will be "string | undefined"
// You will either have to repeat your default value
// Or write a helper type the figures out what is defaulted
const Card: React.FC<CardProps> = ({ size }) => <div>{size}</div>;

Card.defaultProps = {
  size: 'small'
};

// Size is optional to the user
const Usage = () => <Card />;

不使用 React.FC

interface CardProps {
  // Key part right here is to make the defaulted prop not optional
  // this way in your function it won't be undefined
  size: 'small' | 'large';
}

// The type of size will be "string"
const Card = ({ size }: CardProps) => <div>{size}</div>;

// Typescript can use this defaultProps to determine what is optional
// for the user of your component.
Card.defaultProps = {
  size: 'small'
};

// Size is optional to the user
const Usage = () => <Card />;

我的元件繼承自 HTML 元素,而且面板中 prop 過多!我要如何移除一些?

您可以將篩選器新增至 react-docgen-typescript-plugin,以省略來自 @types/react 的任何項目。

.storybook/main.js

{
    typescript: {
        check: false,
        reactDocgen: 'react-docgen-typescript',
        reactDocgenTypescriptOptions: {
            propFilter: (prop) => {
                if (prop.name === 'children') {
                    return true;
                }

                if (prop.parent) {
                    return (
                        !/@types\/react/.test(prop.parent.fileName) &&
                        !/@emotion/.test(prop.parent.fileName)
                    );
                }
                return true;
            },
        },
    },
}

靈感

程式碼很大程度受到以下程式碼的啟發(複製自)