React初心者が、StorybookでQRコードを表示するAddonを作ってみた

デザイン部所属のフロントエンドエンジニア竹内美帆です。
アイスタイルでは、コンポーネント開発自体をVue.jsで作業しており、最近Storybookを導入し始めてみました。
利用してて感じるのは日本語のドキュメントが少ないということです。Addon作って何か情報共有したら、勉強にもなるし、誰かの役に立つかなと思い実装してみました!
storybookには、すでに素晴らしいAddonが用意されており、Addon Galleryから閲覧できます。

開発したStorybookのAddon

デバイス確認でブラウザのQRコード表示するアドオンでいちいち押すの面倒だし、違うタブに移動するとQRコードが消えたりしたので最初から表示させとけという私のニーズから開発しました。

storybook-addon-qrcodeのキャプチャ画像

npmにパッケージとして登録しましたので、ぜひstorybook利用するときはインストールしてみてください!

storybook-addon-qrcodeを見る
https://www.npmjs.com/package/storybook-addon-qrcode

前提Reactスキル

Reactについては参考文献記載の本で基礎を勉強、ちょっとしたTodoアプリ作っただけです。JavaScript、ES6は、初級~中級くらい。

Addon本体のregister.js

Addonのスクリプトをregister.jsというファイルを作り実装しました。

書いたものは、Storybookの設定ディレクトリにあるaddons.jsに呼び出すことで実行されます。
Addonの利用に関しては、Using Addonsをご覧ください。

register.jsの中身

思ったより少ないコード(36行)で出来上がりましたので、1つずつ見て行きます。
何インストールしているとか詳細はstorybook-addon-qrcode(gitHub)のほうをご覧ください。

import React, { Component } from 'react';

StorybookUIがReactなので、Addonも必然的にReactを呼びます。

import addons from '@storybook/addons';

addon作るときはAPIが用意されているので呼び出し、StorybookのUIやパネル、プレビューなどを操作できます。

import qrcode from 'qrcode';

QRコードを表示するために、qrcode – npmを利用します。

addons.register('qr-code',
  function() {
    addons.addPanel('qr-code',{
      title: 'qr code',
      render: function(active) {
        const sampleOn = active.active;
        if(sampleOn) {
          const url = location.href;
          return(<QrCodeImage url={url} />);
        }
      },
    });
  }
);

StorybookUIのパネルに追加するには、addPanelを利用し、パネルの名前(title)と何を表示するか(render)の値を引き渡します。
registerは、storybookAPIにアクセスできるようにし、renderには後述するReactComponentを引き渡しています。このrenderの部分に表示したいコンポーネントを設定します。
urlは今表示しているURLを取得し、コンポーネントに引き渡します。

sampleOnがif文で囲われていますが、このパネル自体がアクティブかアクティブでないかを判定し、アクティブの場合のみに表示するようにしています。

class QrCodeImage extends Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    qrcode.toCanvas(canvas, this.props.url , function (error) {
      if (error) { console.error(error) }
    });
  }

  render() {
    return (
      <canvas id="canvas"></canvas>
    );
  }
}

上記で引き渡されていたコンポーネントですが、インストール済みのqrcodeを利用、canvasにQRコードを描画し、返しています。
Reactでは、コンポーネントを作成するときにclassを利用し、Componentを継承します。
Vue.jsと同じように処理の流れ(ライフサイクル)が決まっており、今回はrenderのすぐ後にDOMへのアクセスが可能になる「componentDidMount」で実行してみました。

インストール時にコンパイルがかかるように設定

StorybookのNotesというAddonを見ると、install時にsrcにあるregister.jsをコンパイルし、素のJavaScriptとして動作するようにされていました。

確かに、このままインストールして設置しただけだと、コンパイルはかからないですね。Storybook側に、node_modulesの中に入っているものを呼び出すので、コンパイルかけてあげたほうが利用者側も便利ですね。

package.jsonのscriptsに下記コードを追加しました。

  "scripts": {
    "prepare": "babel src -d dist"
  },

今回初めて知ったのですが、scriptsにprepareというものを入れておくと、install時に実行してくれるとのことです。

Vue.jsと違い、Reactのコンパイルはbabelを利用します。
babelに関しては下記Quita記事が分かりやすかったので、参照してみてください。
Babel を使って React の jsx をコンパイルする(@tanaka0325)

インストール時に、prepareが実行されて無事distディレクトリが出来ているかと思います。
あとは、これを呼び出すだけです!!

開発してみた感想

初めてAddonを作ったのもそうですが、npmへの公開も初めてでした。
npmに公開するところも悪戦苦闘しましたが、あのnpmに自分のコードが上がっていると思うと少し誇らしくなりました。メールアドレス登録すれば誰でもできるのですが笑

このAddonを作成するのにいろいろ質問したり、コードレビューしてもらったり協力いただいた高田さん、久保田さん、田中さん、ありがとうございました!カッコイイヘッダー画像のアドバイスしてくれた細江さんもありがとうございます!

Reactもコンポーネントとかの書き方が違うだけで、色々参考にしながら書いたのでそこまで難しくはなかったです。
この記事を読んで1人でもいいので、StorybookでAddon作ろうかなという方がでていただければうれしいです。

参考文献

デザイン部所属フロントエンドエンジニア。コーディング歴10年超え。ガリガリ実装より、環境の標準化ガイドライン作り、新卒・中途コーディング研修などに注力。HTML好きで結構前ですが、HTML5/CSS3コンテスト入賞経験もあり。でもたまにはJavaScriptやPHPでの実装もやりたくなる。2019年3月現在はwebpack-dev-serverでのサーバー起動などを勉強中。