LoginSignup
9
9

More than 3 years have passed since last update.

Create React AppのTypeScript対応プロジェクトにStorybook v6を導入した

Last updated at Posted at 2020-12-05

はじめに

Qiita初投稿なので最初に自己紹介。
都内のWEB系企業でアプリ開発をしているスズキと申します。
商社で約4年間営業として働いていたのですが、2020年7月のコロナ真っ只中にエンジニア転職しました。

記事投稿のようなアウトプットはこれまで面倒でやっていなかったのですが、知識の定着や同じ問題が起こったときの見返しメモとして有用だと思い、このたび始めた次第です。

月2くらいのペースで投稿していけたらと考えています。

ということで本題に入ります!

今回とりあげたのは、Storybookというフロントエンド開発で最も有名なUI開発ツールです。
Githubのスターが55kを超えるような超有名ツールみたいなのですが、恥ずかしながら今まで全く知りませんでした。

私の場合はアプリのUI開発にあたるのですが、開発フローのなかでちょっとした手間が結構あるんですよね。
例えば、以下のようなことです。
・APIより先にUIができてしまったときの表示確認。
・デザイナーやディレクターとのUI微修正のやりとり。
・プロジェクト内のコンポーネントがアプリ内のどれにあたるのかわからない。

プロダクトと切り離したUI開発ができるツールとかないんかな。。。と探していたところで見つけたのがこのStorybookでした。

React Native(Expo)で早速検証したかったのですが、Storybook v6の導入に関する情報がほとんどなかったので、手始めにReact(Create React App)で検証することにしました。

インストール

プロジェクト作成の前にNode.jsとyarnがインストールされていることを確認します。
以下のコマンドでプロジェクトを作成することができます。

npx create-react-app my-app --template typescript

cd my-appでフォルダに移動し、以下のコマンドでStorybookを導入することができます。

npx sb init 

*Qiitaの様々な記事でnpx -p @storybook/cli sb initのコマンドが使われていますが、こちらはv5までの導入方法になります。今回はv6の導入記事なので、npx sb initを実行してください。

以下のコマンドを実行することでStorybookが起動します。

yarn storybook

スクリーンショット 2020-12-05 17.28.56.png

Storybookの関連ファイルとフォルダ

ここまでのコマンド実行でプロジェクト直下に.storybook、src直下にstoriesというフォルダが作成されていると思います。
スクリーンショット 2020-12-05 17.35.07.png

.storybookフォルダ内のファイル構成はv6から、main.jsとpreview.jsの2ファイルになりました。
main.jsではstoryのパスや適用するアドオンを定義し、preview.jsでは全ストーリーに対してグローバルにアドオンを適用したりすることができます。

main.js

module.exports = {
  "stories": [
    "../src/**/*.stories.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/preset-create-react-app"
  ]
}

preview.js

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
}

Storyの作成

今回はbuttonコンポーネントを使って簡単なStoryを作成します。
src直下にcomponentsフォルダを作成し、componentsフォルダの中でさらにコンポーネント単位でフォルダを作成します。
例えば、今回のケースでは、src/components/Buttonの中にButton.tsx, Button.css, Button.stories.tsxの3つファイルを作成します。

Button.tsx

import React from 'react'
import './Button.css'

type Props = {
  variant: string
}

const Button: React.FC<Props> = (props) => {
  const {variant, children, ...rest} = props
  return (
    <button className={`button ${variant}`} {...rest}>
      {children}
    </button>
  )
}

export default Button

Button.css

.button {
  border: none;
  color: white;
  padding: 15px 32px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 16px;
  border-radius: 4px;
  cursor: pointer;
}

.primary {
  background-color: #008cba;
}
.secondary {
  background-color: #e7e7e7;
  color: black;
}

Button.stories.tsx

import React from 'react'
import Button from './Button'

export default {
  title: 'form/Button',
  compoent: Button,
}

const Template = args => <Button {...args}/>

export const PrimaryA = Template.bind({})
PrimaryA.args = {
  variant: 'primary',
  children: 'Primary Args'
}

3箇所にわけて説明します。

export default {
  title: 'form/Button',
  compoent: Button,
}

titleはStorybook内のサイドバーでの表示名を表します。
スクリーンショット 2020-12-05 20.51.09.png
componentにはimportしたtsxファイル名を指定します。

const Template = args => <Button {...args}/>

こちらで各ストーリーのテンプレートを作成します。作成していくストーリーには、全てこのテンプレートを使用します。

export const PrimaryA = Template.bind({})
PrimaryA.args = {
  variant: 'primary',
  children: 'Primary Args'
}

PrimaryAというストーリーを作成しました。
作成したTempleteをbindし、variantとchildrenにそれぞれ引数を与えます。
すると、Storybook内に作成したストーリーのコンポーネントが表示されます。
スクリーンショット 2020-12-05 20.58.43.png

Button.stories.tsxにさらに2つのストーリーを追加します。

export const LongPrimaryA = Template.bind({})
LongPrimaryA.args = {
  ...PrimaryA.args,
  children: 'Long Primary Args'
}

export const SecondaryA = Template.bind({})
SecondaryA.args = {
  variant: 'secondary',
  children: 'Secondary Args'
}

さきほどのコンポーネントと同様に、Storybookへ反映されます。
スクリーンショット 2020-12-05 21.03.46.png
スクリーンショット 2020-12-05 21.03.05.png

各種アドオンの紹介

Storybookには便利なアドオン(拡張機能)がいろいろ揃っています。
何種類かアドオンをいれて確かめてみたので、いくつか紹介します。

アドオンのインストールには以下のコマンドを用い、インストール後はmain.jsに使用するアドオンを追記してください。
*@storybook/addon-docsを使用する際に、@storybook/addon-controlsがないとエラーがでました。

yarn add -D ~

main.js

  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-actions",
    "@storybook/preset-create-react-app",
    "@storybook/addon-viewport",
    "@storybook/addon-docs",
    "@storybook/addon-essentials",
    "@storybook/addon-controls",
    "@storybook/addon-knobs",
    "@storybook/addon-a11y"
  ]

addon-viewport

デフォルトではSmall, Medium, Large, Tabletの4つから画面サイズを選ぶことができるのですが、以下のようにINITIAL_VIEWPORTSをインポートすると、登録されている市販端末の画面サイズでコンポーネントの表示を確認することができます。


import {addParameters} from '@storybook/react'
import {INITIAL_VIEWPORTS} from '@storybook/addon-viewport'

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
}

addParameters({
  viewport: {
    viewports: INITIAL_VIEWPORTS,
  }
})

スクリーンショット 2020-12-05 21.51.54.png

addon-console

ストーリーでonClickイベントに指定したconsole.logをStorybook内で出力することができます。

Button.stories.tsx

PrimaryA.args = {
  variant: 'primary',
  children: 'Primary Args',
  onClick: () => console.log('ButtonClicked')
}

preview.js

import {addDecorator} from '@storybook/react'
import {withConsole} from '@storybook/addon-console'

addDecorator((storyFn, context) => withConsole()(storyFn)(context))

スクリーンショット 2020-12-05 22.10.57.png

addon-docs

Storybook内のdocsタブで、コンポーネントに関するドキュメントをまとめることができます。
スクリーンショット 2020-12-05 22.16.33.png

addon-knobs

こちらのアドオンでは、Storybook下部のknobsタブ内でpropsを手動で変更することができます。
以下では、Buttonのdisabledとchildrenを変更できるようにしました。

preview.js

import {addDecorator} from '@storybook/react'
import {withKnobs} from '@storybook/addon-knobs'

addDecorator(withKnobs)

stories.tsxファイルがv6の書き方だとうまくいかず、v5の書き方だとうまくいきました。
うまく行かなかった理由については調査中です。。。

Button.stories.tsx

export const Knobs  = () => (
  <Button variant='primary' disabled={boolean('Disabled', false)}>
    {text('Label', 'Button Label')}
  </Button>
)

スクリーンショット 2020-12-05 22.45.37.png

addon-a11y

コンポーネントのアクセシビリティを確認することができます。
https://ja.reactjs.org/docs/accessibility.html

preview.js

import {addDecorator} from '@storybook/react'
import {withA11y} from '@storybook/addon-a11y'

addDecorator(withA11y)

スクリーンショット 2020-12-05 22.54.21.png

おわりに

初めての記事作成非常に疲れました。。。
よくいわれることですが、アウトプットしてみると知識の穴がめちゃくちゃ見つかりますね。

記事内容であやしい部分があったら都度修正していきます。

それでは!

9
9
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9