Closed7

Story で Hooks API (useState) 使うと 'Storybook preview hooks can only be called ...' エラーになる件

snakasnaka

問題の箇所の story は以下のようになっていた。エラーが発生するタイミングは onChangeValue が呼び出されたタイミング。

HogeInput/index.stories.tsx
import { useState } from 'react'

import { HogeInput } from '.'

export default {
  component: HogeInput,
  title: 'molecules/HogeInput'
}

export const Default = () => {
  const [, setValue] = useState<number | null>(0)
  const [error, setError] = useState('')

  return (
    <HogeInput
      error={error}
      onSetError={setError}
      initialValue={1}
      onChangeValue={v => setValue(v)}
      name="hogehoge"
    />
  )
}
snakasnaka

story を書き直す

https://storybook.js.org/docs/writing-stories#working-with-react-hooks

このページを参考に story を書き直すと以下のようになった

HogeInput/index.stories.tsx
import { ComponentProps, useState } from 'react'

import { Meta, StoryObj } from '@storybook/react'

import { HogeInput } from '.'

export default {
  component: HogeInput,
  title: 'molecules/HogeInput'
} satisfies Meta<typeof HogeInput>

type Story = StoryObj<typeof HogeInput>

const HogeInputWithHooks = (args: ComponentProps<typeof HogeInput>) => {
  const [, setValue] = useState<number | null>(0)
  const [error, setError] = useState('')

  return <HogeInput {...args} error={error} onSetError={setError} onChangeValue={v => setValue(v)} />
}

export const Default: Story = {
  args: {
    name: 'hogehoge',
    initialValue: 1
  },
  render: args => <HogeInputWithHooks {...args} />
}

これで動くようになった。

snakasnaka

修正のポイント

  • story を StoryObj<typeof Component> 形式に書き換えた 。
  • Hooks API を利用する場合、そのラッパーとなるコンポーネントを用意した。 (上記では HogeInputWithHooks がそれに相当)
  • render プロパティの関数で、そのコンポーネントをレンダリングするように修正した。
snakasnaka

export default ... satisfies Meta<typeof HogeInput> について

Storybook 公式ページのサンプルでは以下のような書き方になっているが、微妙に冗長な気がした。

const meta: Meta<typeof HogeInput> = {
  component: HogeInput,
  title: 'molecules/HogeInput'
}
export default meta

かと言って、 export default: Meta<typeof HogeInput> = のように型を与えることができないので satisfies で型の制約を与えるようにして以下のような書き方にした。

export default {
  component: HogeInput,
  title: 'molecules/HogeInput'
} satisfies Meta<typeof HogeInput>
このスクラップは3ヶ月前にクローズされました