0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

React Native + Expo プロジェクトへのStorybook v6導入検討

Last updated at Posted at 2021-01-15

はじめに

前回の記事(Create React AppのTypeScript対応プロジェクトにStorybook v6を導入した)に引き続き、今回はReact Native + Expo のプロジェクトにStorybook v6を導入できるか検討してみました。

インストール

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

expo init my-project

コマンドを実行するとtempleteを選ぶことができるので、今回はblank (TypeScript)を選択します。

$ expo init my-project
? Choose a template: › - Use arrow-keys. Return to submit.
    ----- Managed workflow -----
    blank                 a minimal app as clean as an empty canvas
❯   blank (TypeScript)    same as blank but with TypeScript configuration
    tabs (TypeScript)     several example screens and tabs using react-navigation and TypeScript
    ----- Bare workflow -----
    minimal               bare and minimal, just the essentials to get you started
    minimal (TypeScript)  same as minimal but with TypeScript configuration

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

npx -p @storybook/cli sb init --type react

*Create React Appではnpx sb initコマンドでv6が導入されましたが、expoではv5が導入されてしまうので注意が必要です。

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

yarn storybook

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

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

ここまでのコマンド実行でプロジェクト直下に.storybookとstoriesというフォルダが作成されていると思います。
*Create React Appだとsrc/storiesというディレクトリ構成ですが、Expoの場合だとプロジェクト直下にstoriesフォルダが作成されます。

スクリーンショット 2021-01-15 22.00.34.png

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

main.js

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

preview.js

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

Storyの作成

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

Button.tsx

import React from 'react';
import { Button, ScrollView, View } from 'react-native';

const ButtonNative = (props) => {
  const { color, title, age, ...rest } = props;
  return (
    <ScrollView style={{ height: 1000 }}>
      <View style={{ width: 300 }}>
        <Button
          buttonStyle={{ width: 100 }}
          color={color}
          title={title}
          {...rest}
        />
      </View>
    </ScrollView>
  );
};

export default ButtonNative;

当たり前ですが、上記のようにScrollViewなどのReact Naviveコンポーネントにも対応しています。

Button.stories.tsx

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

export default {
  title: 'native/ButtonNative',
  compoent: ButtonNative,
};

const Template = (args) => <ButtonNative {...args} />;

export const PrimaryA = Template.bind({});
PrimaryA.args = {
  color: 'blue',
  title: 'Primary Args',
};

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

export const SecondaryA = Template.bind({});
SecondaryA.args = {
  color: 'red',
  title: 'Secondary Args',
};

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

export default {
  title: 'native/ButtonNative',
  compoent: ButtonNative,
};

titleはStorybook内のサイドバーでの表示名を表します。
スクリーンショット 2021-01-15 22.45.45.png

componentにはimportしたtsxファイル名を指定します。

const Template = (args) => <ButtonNative {...args} />;

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

export const PrimaryA = Template.bind({});
PrimaryA.args = {
  color: 'blue',
  title: 'Primary Args',
};

PrimaryAというストーリーを作成しました。
作成したTempleteをbindし、colorとtitleにそれぞれ引数を与えます。
すると、Storybook内に作成したストーリーのコンポーネントが表示されます。
スクリーンショット 2021-01-15 22.47.43.png

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

PrimaryAのcolorはそのままでtitleのみを変更したり、

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

スクリーンショット 2021-01-15 22.53.29.png

colorとtitleを両方とも変更したりなど、自由にstoryを作ることができます。

export const SecondaryA = Template.bind({});
SecondaryA.args = {
  color: 'red',
  title: 'Secondary Args',
};

スクリーンショット 2021-01-15 22.54.46.png

アドオンの導入

Storybookには便利なアドオン(拡張機能)がいろいろ揃っています。
今回はaddon-knobsというアドオンを導入します。

アドオンのインストールには以下のコマンドを用い、インストール後はmain.jsに使用するアドオンを追記してください。

yarn add -D ~

main.js

module.exports = {
  stories: [
    '../stories/**/*.stories.mdx',
    '../stories/**/*.stories.@(js|jsx|ts|tsx)',
  ],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    '@storybook/addon-knobs',
  ],
};

addon-knobs

こちらのアドオンでは、Storybook下部のknobsタブ内でpropsを手動で変更することができます。
以下では、Buttonのtitle, color, disabledを変更できるようにしました。
*addon-knobsはv6の書き方に対応していないようでしたので、v5の書き方で記載しました。

Button.stories.tsx

export const Knobs = () => (
  <ButtonNative
    title={text('Name', 'ボタン')}
    color={color('Color', 'red')}
    disabled={boolean('Disabled', false)}
  />
);

以下のようにカラーマップから自由に色を変更したり、チェックボックスからDisabled状態に切り替えることができます。
スクリーンショット 2021-01-15 23.04.14.png

スクリーンショット 2021-01-15 23.05.23.png

React Nativeプロジェクトにおけるアドオン

Storybookには、addon-knobsの他にも、addon-viewport, addon-console, addon-a11y, addon-docsなどの便利なアドオンが揃っています(詳しくは以下の記事をご覧ください)。 Create React AppのTypeScript対応プロジェクトにStorybook v6を導入した

しかし、React Nativeでは、なんとこれらのアドオンのほとんどには対応していません...
image.png

せめて市販端末の画面サイズでコンポーネント表示を確認できる、addon-viewportには対応してほしかったのですが...

(以下はCreate React Appで導入した際の画面です)

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

おわりに

ほとんどのアドオンに対応していないことから、現状では、実際のReact Native + ExpoプロジェクトにStorybookを導入するのは難しそうですね...

今後の公式の対応に期待したいと思います。

0
1
0

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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?