Chapter 08

[アドオン編] Actions addon

shingo.sasaki
shingo.sasaki
2020.11.03に更新

Actions addon について

Actions addon は、essentials addons の一つで、 コンポーネントからイベントハンドラ(≒emit) で渡されたデータを表示する アドオンです。

Vueコンポーネントは、emit を通じて、親コンポーネントに対してイベントを伝搬しますが、 Storybook はサンドボックス上にコンポーネントを単独で配置することから、そのままではイベントを受け取ることができません。

そこで、 Actions addon を用いることで、コンポーネントから渡されたアクションオブジェクトをロギングすることにより、親コンポーネントに対する振る舞いを画面上で検証できるようにします。

Header コンポーネントのストーリーを作成する

この章では、これまでの Button コンポーネントからは一度離れて、 Header コンポーネントのストーリーを用いて進めます。

まずはサクッと、 Header コンポーネントのストーリーを作成しましょう。

src/components/Header.stories.js
import Header from './Header'

export default {
  title: 'Header',
  component: Header
}

const Template = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { Header },
  template: `<Header v-bind="$props" /> `
})

export const LoggedIn = Template.bind({})
LoggedIn.args = {
  user: { id: 1, name: 'sasaki' }
}

export const LoggedOut = Template.bind({})
LoggedOut.args = {
  user: {}
}

Header コンポーネントは、ログイン中と思われるユーザ情報を、 Object 型で props で受け取ります。
今回はログイン中とそうでない場合の2通りを用意します。

これで、以下のような2種類のストーリーを確認することができます。

見ての通り、 Controls addon によって、 Control タブに EVENTS が一覧されており、どんなイベントが発火するのかはひと目で分かります。

しかし、これらのイベントがどのタイミングで発火し、どのようなイベントパラメータが飛んでくるのかは判断が付きません。そこからは Actions addon の出番になります。

各種ボタンがクリックされたことを確認できるようにする

一度 Header コンポーネントのコードを見てみましょう。

src/components/Header.vue
<template>
  <header>
    <h1>Vue × Storybook 6 Sample App</h1>
    <div class="buttons">
      <template v-if="user.id">
        <MyButton size="small" label="ログアウト" @onClick="$emit('onLogout', user)" />
      </template>
      <template v-else>
        <MyButton size="small" label="ログイン" @onClick="$emit('onLogin')" />
        <MyButton size="small" label="会員登録" @onClick="$emit('onSignUp')" />
      </template>
    </div>
  </header>
</template>

上記のように、 Header コンポーネントは、以下の3種類のイベントを伝搬します。

  • onLogout (ログアウトするUserオブジェクトを渡してくれる)
  • onLogin
  • onSignUp

現状では、 Storybook 上でデザイン及びイベントの一覧は確認はできても、各ボタンがクリックされたときにどんなイベントが伝搬されるのかを確認できないため、このコンポーネントを使用する親コンポーネントを実装しようにも、ソースコードを読んでみないと使い方がわかりません。

Actions addon を活用することで、ソースコードをまったく見ずとも、コンポーネントの使い方を把握することができます。

まず、 Template 側を修正し、通常のVueコンポーネントの書き方と同じように、イベントハンドリングを行います。

src/components/Header.stories.js
 const Template = (args, { argTypes }) => ({
   props: Object.keys(argTypes),
   components: { Header },
-  template: `<Header v-bind="$props" /> `
+  template: `
+    <Header
+      @onLogout="onLogout"
+      @onLogin="onLogin"
+      @onSignUp="onSignUp"
+      v-bind="$props"
+    />
+  `
 })

このままだと、 Storybook 側は何のイベントを補足すれば良いかわからないので、イベントに関する定義を argTypes に記述します。

src/components/Header.stories.js
 export default {
   title: 'Header'
-  component: Header
+  component: Header,
+  argTypes: {
+    onLogin: {
+      action: 'onLogin'
+    },
+    onLogout: {
+      action: 'onLogout'
+    },
+    onSignUp: {
+      action: 'onSignUp'
+    }
+  }
 }

この状態で、 Storybook を立ち上げ、各種ボタンをクリックしてみましょう。


このように、コンポーネントから伝搬されたイベントを補足し、 Actions タブにログを表示することが出来る上、ログアウトボタンのようにパラメータを持ったイベントの場合はパラメータの詳細まで確認することができます。

全てのイベントを捕捉する

前項で argTypesonLogin onLogout onSignUp を定義する方法はいかがでしたか? 正直かなり面倒ですよね。

前項の書き方は、捕捉したイベントに応じて任意の処理を記述できるので、それによって何らかのインタラクティブを発生させ、より具体的な検証を行えるようにすることもできます。

とはいえ、今回はどのイベントが発生して、どんなパラメータが渡されたかを知りたいだけですので、もっとシンプルな書き方が欲しくなります。

以下は、ストーリー内で発生した全てのイベントを捕捉し、ログインさせる設定です。

src/components/Header.stories.js
export default {
  title: 'Header',
  component: Header,
  parameters: { actions: { argTypesRegex: '.*' } }
}

これだけで、前項と同様の結果を得ることができます。