react + storybookを試してみた

Reactでプロジェクトを開発するため、Component単位でソースを分けるのはすごくいいです。

でもその時、ドキュメンテーションはどうやっていますか?エンジニア以外のメンバーに見せるために、コンポーネント一覧の画面を用意しないとですね。例えばそれぞれの属性とか、色々データーのヴァリエーションとか。

これは、結構、めんどくさい。でもstorybookが助けてくれるので、見てみましょう

install storybook

例えReact プロジェクトで、components/Button.jsにはこんなコードとしよう:

import React from 'react';
import PropTypes from 'prop-types';

function Button(props) {
    const {children, ...other} = props;
    return <button {...other}>{props.children}</button>;
}

Button.propTypes = {
    size: PropTypes.oneOf(['small', 'big'])
};

export default Button;

公式ドキュメントにしたがってインストールする:

npm i --save-dev @storybook/react

package.jsonにコマンドを追加する。

{
  "scripts": {
    "storybook": "start-storybook -p 9001 -c .storybook"
  }
}

storybookをコンフィグ

まず.storybook/config.jsを追加する:

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

function loadStories() {
  require('../stories/index.js');
}

configure(loadStories, module);

storiesにある全てのstoryを全部loadする意味。

storyを追加

strories/の下にindex.jsを追加する

import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
storiesOf('Button', module)
  .add('with text', () => {
    return <Button >Arunoda Susiripala</Button>
  })
  .add('with some emoji', () => (
    <Button ><span role="img" aria-label="so cool">😀 😎 👍 💯</span></Button>
  ));   
> npm run storybook

見ればわかるが:

  1. サイドバーにstory一覧がみれる
  2. 右側にstoryの中身を表示する

knobs

knobは引き手の意味、つまり表示内容を操作できるのね 直接コンポーネントを弄りたい場合は、プラグインを使ったらいい

npm install @storybook/addon-knobs --save-dev

.storybook/addons.jsにプラグインを入れる:

import '@storybook/addon-knobs/register';

最後にstoryの中にプラグインを使う。

import { withKnobs, text, boolean, number } from '@storybook/addon-knobs';

storiesOf('Button', module)
  .addDecorator(withKnobs)
  .add('with text', () => {
    const name = text('Name', 'Arunoda Susiripala');
    return <Button onClick={action('clicked')}>{name}</Button>
  })

knobs panelが追加されるのがわかりました

PropType

react componentのpropsはどう処理する?まずButtonのpropsを定義しましょう

import React from 'react';
import PropTypes from 'prop-types';

const fontSize = {
    small: '12px',
    big: '16px'
};

function Button(props) {
    const {children, ...other} = props;
    return <button {...other} style={{fontSize: fontSize[props.size]}}>{props.children}</button>;
}

Button.propTypes = {
    size: PropTypes.oneOf(['large', 'big']),
    color: PropTypes.string
};

export default Button;

storyにも変更を入れる

import { withKnobs, text, select } from '@storybook/addon-knobs';

storiesOf('Button', module)
  .addDecorator(withKnobs)
  .add('with text', () => {
    const name = text('Name', 'Arunoda Susiripala');
    const size = select('size', ['large', 'small']);
    const color = text('color', 'green')
    return <Button onClick={action('clicked')} size={size} color={color}>{name}</Button>
  })

これで、size, color, nameは全部編集できるようになりました。

snapshot test

まず普通にunit testをやる時:

  1. jest enzymeを使って、unit testを書く
  2. jestでsnapshot testをやる

まずstorybookがない時のsnapshotのやり方をみてみましょう

npm install --save-dev jest react-test-renderer babel-preset-env babel-preset-react

packae.json

"scripts": {
    "test": "jest --no-watchman",
    "storybook": "start-storybook -p 9001 -c .storybook"
},

test spec, __test__/Button.test.jsを追加する

import React from 'react';
import Button from '../components/Button';
import renderer from 'react-test-renderer';

it('renders correctly', () => {
  const tree = renderer
    .create(<Button size="large" color="green">sunderls</Button>)
    .toJSON();
    expect(tree).toMatchSnapshot();
});

presetをbabelrcに追加しないと、jestがtest specをtranspileしてくれない。

{
    "presets": ["env", "react"]
}

npm run testを実行すると、__test__の下に__snapshots__が追加される。中にはbookのtest snapshotがある。

もう一回npm run testを実行すると、↑のsnapshotを比べることになる。たとえばButtonの20pxをうっかりと21pxにしちゃった場合、run testでエラーが吐かれる。とっても便利。(dynamic testingするときは別の話ですが)

storybookに戻ります。storybookの書き方はtest spec に似てるのはお気づきでしょうか。同じくcomponentに必要なpropsをいれてinstance化としてる。そうであれば、ロジックが共有できそう。

storyshotsってプラグインをインストール

npm i -D @storybook/addon-storyshots

storyshots.test.jsを追加

import initStoryshots from '@storybook/addon-storyshots';
initStoryshots({});

npm run testを実行するsnapshotが2個追加される。Buttonの20px21pxにすると、エラーが2個吐かれる。

snapshotを更新するときもあるので、package.jsonでコマンドを追加すれば

 "update-snapshot": "jest --updateSnapshot --no-watchman"

うん、便利ですね。

サマリー

以上storybookの紹介でした。いかがでしょうか。自分のプロジェクトは結構使っていい感じでしたので、よければぜひ試してみてください。

以上では各投稿者の観点であり、zanp.lifeに責任負い兼ねます。

#js#programming#javascript#react#storybook#web#frontend

startup  2018-9-9