Intro to Storybook
  • はじめに
  • 単純なコンポーネント
  • 複合的なコンポーネント
  • データ
  • 画面
  • デプロイ
  • テスト
  • アドオン
  • まとめ
  • 貢献する
Framework:
ReactReact NativeVueAngularSvelteEmber

画面を作る

コンポーネントをまとめて画面を作りましょう
このコミュニティの翻訳は、最新のストーリーブックバージョンにまだ更新されていません。この翻訳の日本語ガイドの変更を適用して、更新にご協力ください。 Pull requests 彼らは大歓迎です.

今までボトムアップ (小さく始めてから複雑性を追加していく) で UI の作成に集中してきました。ボトムアップで作業することで、Storybook で遊びながら、それぞれのコンポーネントを切り離された環境で、それぞれに必要なデータを考えながら開発することができました。サーバーを立ち上げたり、画面を作ったりする必要は全くありませんでした!

この章では Storybook を使用して、コンポーネントを組み合わせて画面を作り、完成度を高めていきます。

ネストされたコンテナーコンポーネント

このアプリケーションはとても単純なので、作る画面は些細なものです。(Redux から自分でデータを取得する) TaskList をレイアウトして、Redux からの error フィールド (サーバーとの接続に失敗したときに設定される項目だと思ってください) を追加するだけです。それでは components フォルダーに InboxScreen.js ファイルを作りましょう:

// src/components/InboxScreen.js

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';

import TaskList from './TaskList';

export function PureInboxScreen({ error }) {
  if (error) {
    return (
      <div className="page lists-show">
        <div className="wrapper-message">
          <span className="icon-face-sad" />
          <div className="title-message">Oh no!</div>
          <div className="subtitle-message">Something went wrong</div>
        </div>
      </div>
    );
  }

  return (
    <div className="page lists-show">
      <nav>
        <h1 className="title-page">
          <span className="title-wrapper">Taskbox</span>
        </h1>
      </nav>
      <TaskList />
    </div>
  );
}

PureInboxScreen.propTypes = {
  /** The error message */
  error: PropTypes.string,
};

PureInboxScreen.defaultProps = {
  error: null,
};

export default connect(({ error }) => ({ error }))(PureInboxScreen);

さらに、App コンポーネントを InboxScreen を描画するように変更します (いずれはルーターにどの画面を表示するか決めてもらいますが、今は気にしないでください):

// src/App.js

import React from 'react';
import { Provider } from 'react-redux';
import store from './lib/redux';

import InboxScreen from './components/InboxScreen';

import './index.css';
function App() {
  return (
    <Provider store={store}>
      <InboxScreen />
    </Provider>
  );
}
export default App;

しかし興味深いのは、InboxScreen のストーリーに関してです。

前に示したように TaskList コンポーネントは、表示用のコンポーネントである PureTaskList を描画するコンテナーです。定義上コンテナーコンポーネントはコンテキストが渡されたり、サービスに接続したりすることを想定するため、切り離された環境においてはそのままでは描画できません。つまりコンテナーを Storybook で描画するには、コンポーネントに必要なコンテキストやサービスをモック化 (例えば、振る舞いを模倣させるなど) しなければならないということです。

TaskList を Storybook に置いたときには、コンテナーではなく、PureTaskList を描画することにより、この問題を回避しました。同じように PureInboxScreen を Storybook に描画してみます。

しかし、PureInboxScreen には問題があります。PureInboxScreen が表示用コンポーネントであっても、その子供である TaskList は表示用ではないのです。つまり、PureInboxScreenが「コンテナー性」により汚染されたと言えます。なので、InboxScreen.stories.js を以下のようセットアップすると:

// src/components/InboxScreen.stories.js

import React from 'react';

import { PureInboxScreen } from './InboxScreen';

export default {
  component: PureInboxScreen,
  title: 'InboxScreen',
};

const Template = args => <PureInboxScreen {...args} />;

export const Default = Template.bind({});

export const Error = Template.bind({});
Error.args = {
  error: 'Something',
};

Error ストーリーは正しく動いていますが、Default ストーリーには問題があります。それは TaskList に接続するべき Redux のストアがないためです。(同様に PureInboxScreen を単体テストしようとしても同じことが起こります。)

壊れている Inbox

この問題を回避する方法の 1 つは、コンテナーコンポーネントをアプリケーションの最上位にのみ描画し、代わりにコンポーネント階層の下層に必要なデータをすべて上位のコンポーネントから渡すことです。

ですが、開発ではきっとコンポーネント階層の下位の層でコンテナーを描画する必要が出てくるでしょう。アプリケーション全体、もしくは大部分を Storyook で描画したいなら、解決策が必要です。

補足として、データを下の階層に渡していくことは正当な手法です。GraphQL を使う場合は特に。Chromatic を作る際にはこの手法で 800 以上のストーリーを作成しました。

デコレーターを使用してコンテキストを渡す

ストーリーの中で InboxScreen に Redux のストアを渡すのは簡単です!モック化したストアをデコレーター内部で使用します:

// src/components/InboxScreen.stories.js

import React from 'react';
import { Provider } from 'react-redux';
import { action } from '@storybook/addon-actions';
import { PureInboxScreen } from './InboxScreen';
import * as TaskListStories from './TaskList.stories';

// A super-simple mock of a redux store
const store = {
  getState: () => {
    return {
      tasks: TaskListStories.Default.args.tasks,
    };
  },
  subscribe: () => 0,
  dispatch: action('dispatch'),
};

export default {
  component: PureInboxScreen,
  decorators: [story => <Provider store={store}>{story()}</Provider>],
  title: 'InboxScreen',
};

const Template = args => <PureInboxScreen {...args} />;

export const Default = Template.bind({});

export const Error = Template.bind({});
Error.args = {
  error: 'Something',
};

同様に ApolloRelay など、他のデータライブラリー向けのモックコンテキストも存在します。

Storybook で状態を選択していくことで、問題なく出来ているか簡単にテストできます:

コンポーネント駆動開発

まず、一番下の Task から始めて、TaskList を作り、画面全体の UI が出来ました。InboxScreen ではネストしたコンテナーコンポーネントを含み、一緒にストーリーも作成しました。

コンポーネント駆動開発 (CDD) はコンポーネント階層を上がるごとに少しずつ複雑性を拡張していきます。利点としては、開発プロセスに集中できること、UI の組み合わせの網羅性を向上できること、が挙げられます。要するに、CDD によって、高品質で複雑な UI を作ることができます。

まだ終わりではありません。UI を作成しても仕事は終わりません。長期間にわたり耐久性を維持できるようにしなければなりません。

Git へのコミットを忘れずに行ってください!
Keep your code in sync with this chapter. View 05aa2ef on GitHub.
Is this free guide helping you? Tweet to give kudos and help other devs find it.
Next Chapter
デプロイ
Storybook をインターネット上にデプロイする方法を学びましょう
✍️ Edit on GitHub – PRs welcome!
Docs
Documentation
Add Storybook to your project in less than a minute to build components faster and easier.
reactvueangularweb-components
Tutorial
Tutorials
Learn Storybook with in-depth tutorials that teaches Storybook best practices. Follow along with code samples.
Learn Storybook now
Storybook
The MIT License (MIT). Website design by @domyen and the awesome Storybook community.
StorybookDocsTutorialsReleasesAddonsBlogGet involvedUse casesSupportTeam
Subscribe
Get news, free tutorials, and Storybook tips emailed to you.

Maintained by
Chromatic
Continuous integration by
CircleCI
Hosting by
Netlify