Sassyブログ

埼玉県在住のシステムエンジニアです。多ジャンルなブログですが、基本的にはIT関連の内容を中心に他のちょいちょい他ジャンルの記事も発信していきます。

StorybookでknobsからControlsに書き換える

Storybook上でPropsの値を変更して表示などの確認を行う際にはaddon-knobsをインポートして使っていましたが、今後廃止予定となるため今後はControlsを使って実装するようになっていくかと思います。

既にaddon-knobsは deprecated となっています。

www.npmjs.com

そのため、Controlsに書き直してみます。

Storybook公式サイトにドキュメントがあります。

storybook.js.org

まずは以下のような OriginalComponent というコンポーネントがあるとします。

src/components/OriginalComponent/OriginalComponent.tsx

const OriginalComponent = ({ hoge, fuga, ref }: {hoge: string; fuga: boolean; ref: MutableRefObject<HTMLElement | undefined>}) => {
    return (<OriginalSubComponent hoge={hoge} fuga={fuga} ref={ref}/>)
}

これをKnobsを使って作成したStrorybookは以下になります。

src/components/OriginalComponent/OriginalComponent.stories.tsx

import { withKnobs, text, boolean } from '@storybook/addon-knobs';
・・・省略

export default {
    title: 'originl component'
    component: OriginalComponent,
    decorators: [withKnobs],
}

export const Default: Story<OriginalProps> = (args) => {
  return (
      <OriginalComponent hoge={text('hoge', 'abcdefg')} fuga={boolean('fuga', false)} ref={{} as MutableRefObject<HTMLElement | undefined>} />
  );
};

Default.storyName = 'OriginalComponent'

ではControlsを使ったStorybookに書き換えてみましょう。

src/components/OriginalComponent/OriginalComponent.stories.tsx

export default {
    title: 'originl component'
    component: OriginalComponent,
}

export const Default: Story<OriginalProps> = (args) => {
  return (
      <OriginalComponent {...args} ref={{} as MutableRefObject<HTMLElement | undefined>} />
  );
};

Default.args = {
  hoge: "",
  fuga: false,
};

Default.storyName = 'OriginalComponent'

このように書き換えられます。

ここでControlsに書き換える上でいくつかの問題にあたりました。

1つ目はDefault関数の中で OriginalComponentref だけは Default.args から受け取らず別で渡しているという点です。

これを Default.args に渡して <OriginalComponent {...args} />のようにしてしまうと画面から値を変更しようとしたときに Uncaught TypeError: Converting circular structure to JSON という内容でJSON循環参照エラーが発生してしまい画面が表示されなくなってしまいました。

そのため上記コード例のように <OriginalComponent {...args} ref={{} as MutableRefObject<HTMLElement | undefined>} /> としてあげる必要があります。

念のためダメなパターンのコード全体を挙げておきます。

src/components/OriginalComponent/OriginalComponent.stories.tsx

export default {
    title: 'originl component'
    component: OriginalComponent,
}

export const Default: Story<OriginalProps> = (args) => {
  return (
      <OriginalComponent {...args} />
  );
};

Default.args = {
  hoge: "",
  fuga: false,
  ref: {} as MutableRefObject<HTMLElement | undefined>
};

Default.storyName = 'OriginalComponent'

このようにするとエラーでStorybookが表示されません。

なので分けるようにして対応しました。

2つ目はDefault.argsに渡すオブジェクトのプロパティに更にobjectを渡すとその中のbooleanがいい感じになってくれません。

例えば

Default.args = {
  fuga: false,
};

のようにすると、Storybookが fugaboolean と判断してトグルのUIとして表示してくれます。

f:id:y_saiki:20220128134117p:plain

しかし以下のようにすると、そうなってくれません。

Default.args = {
  fuga: {
    fuga2: false
  },
};

文字列として認識されてしまいます。

おそらくこれに関してはControls単体では上手くできず argTypes というStorybookに型を推論させるための設定を行うことでできるのではないかなと考えてます。

storybook.js.org

個人的には簡単な構造であればKnobsと比べると比較的楽に実装でき、複雑な構造の型の値を変更して表示を確認したいとなると少しコーディングが増えるなというような印象でした。

もう少し色々と触ってみてControls周りの知見を増やしていきたいなと思います。