storybook: Cannot use React hooks directly inside a story
Describe the bug
Cannot use hooks directly in a story, fails with Hooks can only be called inside the body of a function component.
To Reproduce
Example code:
import React from 'react'
import { storiesOf } from '@storybook/react'
const stories = storiesOf('Hooks test', module)
const TestComponent: React.FC = () => {
const [state, setState] = React.useState(5)
return (
<button onClick={() => setState(state + 1)}>
{state}
</button>
)
}
stories.add('this story works', () => <TestComponent />)
stories.add('this story fails', () => {
const [state, setState] = React.useState(5)
return (
<button onClick={() => setState(state + 1)}>
{state}
</button>
)
})
Expected behavior First story works OK, second story fails on initial render
Versions
@storybook/react@4.1.13
react@16.8.2
react-dom@16.8.2
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 54
- Comments: 56 (20 by maintainers)
Commits related to this issue
- Remove Modal storybook, depends on hooks which dont function well with addons https://github.com/storybookjs/storybook/issues/5721 — committed to GCTC-NTGC/TalentCloud by Khristophor 5 years ago
We’ve experienced the same issue, and this is a simple hack we do to workaround it.
I agree it would be much better for it to be natively supported without hacks. If the maintainers agree too then maybe I can find some time to come up with a PR 🙂.
Adding the following to my .storybook/config.js worked for me
addDecorator((Story) => <Story />)For those here googling the error message:
I got this error when a changing a class component to a functional component with hooks and
useStatewas incorrectly importing from@storybook/addons. I needed it to come fromreactrather than@storybook/addons… auto-import fail.Not sure this is a bug. I believe, and I could be wrong, the second argument of
stories.addis expecting a function to return a component and not an actual React component. Try moving your function component to the outside, you should have some success…Example
My info addon doesn’t break provided I added the Story decorator last.
Ta-da!! I just released https://github.com/storybookjs/storybook/releases/tag/v5.2.0-beta.10 containing PR #7571 that references this issue. Upgrade today to try it out!
You can find this prerelease on the
@nextNPM tag.Closing this issue. Please re-open if you think there’s still more to do.
@tmikeschu it’s because the
<Story />wraps the code inReact.createElementwhich is necessary for hooks.I was having this exact same issue. The fix is to capitalize the named story export.
import React from 'react'; import Foo from './Foo'; export default { title: 'Foo'; }; export const Basic = () => <Foo />The docs say capitalization is recommended but it’s necessary if you want that warning to go away.
In my case, the problem was that I forgot to import the hook I was using.
======================================
Do not use arrow function to create functional components. Do as one of the examples below:
Or
If you have problems with “ref” (probably in loops), the solution is to use forwardRef():
Yet another workaround:
I have a utility component called
UseStatedefined like this:And I use it in the stories like this:
But I like @kevin940726 's workaround the best
Also watch out for IDE autoimport feature, instead of importing
useStatefrom:VSC imported it from:
@adeelibr https://github.com/storybookjs/storybook/blob/17dcfb84194c9876d4452aae123443f9748f62b6/examples/official-storybook/stories/demo/button.stories.mdx#counter-w-code
I’m unable to get the story to re-render on state change. Force re-rendering doesn’t work either.
@Keraito No I’m pretty sure the error is correct.
It’s because we’re calling the function out of the context of react, aka storybook will call the function like so:
not
Quite possibly if we’d initiate it like that it might work.
Right now @gabefromutah’s advice is sound.
Here’s the actual line of code: https://github.com/storybooks/storybook/blob/next/app/react/src/client/preview/render.js#L24
If someone wants to experiment to make this work, that’s the place to start, I think.
how can this be achieved in MDX?
it sounds like there’s some issue with using hooks with knobs. If anybody can provide a simple repro, I’d be happy to take a look at it
To display the source code of components with hooks
@shilman Have you tried the example I posted earlier? Here is the snippet:
Its using the old API, but should be easy to transform to the latest API for testing. You could find the expected behaviour from the original post.
While this code works well for React Hooks
It does not work well with
@storybook/addon-info:This makes this workaround unusable. Any ideas? Storybook 5.1.0-beta.0
This was my workaround to this problem:
As I mentioned is still a workaround, but it does work and don’t break the
infoaddon. (I haven’t tested other addons)@kevin940726 that would be awesome 👍
I created a simple class to work with to fix this:
and use:
@shiranZe sure do: https://github.com/storybookjs/storybook/blob/next/examples/official-storybook/stories/demo/button.stories.js#L26
If anyone else is still getting this, i found that the issue seems to be adding prop types to a functional component.
For some reason commenting out
.propTypesseems to make it work. Not sure if it’s an issue with the prop types parsing for documentation or something else.