storybook: Cannot use SB hooks (`useArgs`) in React component rendered inside decorator or render function.
Describe the bug
To Reproduce Steps to reproduce the behavior:
- Create a sample app using CRA (I am using typescript)
- Run
npx sb initto setup storyboard - Install
@storybook/apito getuseArgshook. - Use the code snippet below in the
Button.stories.tsx. - Notice the error on
Hellocomponent.
Storybook preview hooks can only be called inside decorators and story functions.
Error: Storybook preview hooks can only be called inside decorators and story functions.
at invalidHooksError (http://localhost:6007/vendors~main.38cdb582067630c38066.bundle.js:18317:10)
at getHooksContextOrThrow (http://localhost:6007/vendors~main.38cdb582067630c38066.bundle.js:18328:11)
at useStoryContext (http://localhost:6007/vendors~main.38cdb582067630c38066.bundle.js:18521:31)
at useArgs (http://localhost:6007/vendors~main.38cdb582067630c38066.bundle.js:18549:27)
at Object.Template (http://localhost:6007/main.86e3cb3589897769072c.hot-update.js:136:96)
at renderWithHooks (webpack://storybook_docs_dll//Users/shilman/projects/baseline/storybook/node_modules/react-dom/cjs/react-dom.development.js?:2546:153)
at mountIndeterminateComponent (webpack://storybook_docs_dll//Users/shilman/projects/baseline/storybook/node_modules/react-dom/cjs/react-dom.development.js?:2831:885)
at beginWork (webpack://storybook_docs_dll//Users/shilman/projects/baseline/storybook/node_modules/react-dom/cjs/react-dom.development.js?:3049:101)
at HTMLUnknownElement.callCallback (webpack://storybook_docs_dll//Users/shilman/projects/baseline/storybook/node_modules/react-dom/cjs/react-dom.development.js?:70:102)
at Object.invokeGuardedCallbackDev (webpack://storybook_docs_dll//Users/shilman/projects/baseline/storybook/node_modules/react-dom/cjs/react-dom.development.js?:90:45)
Expected behavior It should work
Screenshots

Code snippets
const Template: Story<ButtonProps> = (args) => {
// removing this works everywhere
const [_, updateArgs] = useArgs();
// use hook
return <Button {...args} />;
};
// works without any issue
export const Small = Template.bind({});
Small.args = {
size: 'small',
label: 'Button',
};
// throws error
export const Hello = () => {
return <Small {...(Small.args as any)} />;
};
System: Environment Info:
System: OS: macOS 10.15.5 CPU: (16) x64 Intel® Core™ i9-9980HK CPU @ 2.40GHz Binaries: Node: 13.10.1 - ~/.nvm/versions/node/v13.10.1/bin/node Yarn: 1.22.4 - /usr/local/bin/yarn npm: 6.13.7 - ~/.nvm/versions/node/v13.10.1/bin/npm Browsers: Chrome: 84.0.4147.125 Firefox: 77.0.1 Safari: 13.1.1 npmPackages: @storybook/addon-actions: ^6.0.5 => 6.0.5 @storybook/addon-essentials: ^6.0.5 => 6.0.5 @storybook/addon-links: ^6.0.5 => 6.0.5 @storybook/client-api: ^6.0.6 => 6.0.6 @storybook/node-logger: ^6.0.5 => 6.0.5 @storybook/preset-create-react-app: ^3.1.4 => 3.1.4 @storybook/react: ^6.0.5 => 6.0.5
Additional context Add any other context about the problem here.
About this issue
- Original URL
- State: open
- Created 4 years ago
- Comments: 45 (18 by maintainers)
@suparngp Good sleuthing. You need a different
useArgs:Is there an equivalent for Vue? I’m running into basically the same thing but I need it in vue.
@kylegach
The TLDR of the limitation is you cannot use the Storybook Hooks in React components (that are rendered by decorators or render functions). You can use the hooks in the render functions/decorators themselves of course.
So for instance if you wanted to make a complex decorator that renders a bunch of stuff and needs args, you might refactor the UI into a component and render that component in the decorator. In that case you would need to call
useArgsin the decorator and pass the result into the component as prop.Extra notes: Some people do this just purely for linting reasons, because Eslint thinks our hooks are actually React hooks, but it doesn’t think the decorator / render function is a React component. The simplest solution to that problem is simply to write the render/function in a way that looks more like a component (which it is actually):
thank you!
unfortunately the solution you suggested gives a storyblok error for me:
Storybook preview hooks can only be called inside decorators and story functions.I went with a lazy solution for now:
// eslint-disable-next-line😆Of course after I write up a better description of the issue, I go and find a solution. The solution seems to be to switch from the
@storybook/manager-apiimport to@storybook/preview-api. This has the necessaryuseArgshook.Here is a full working example in v7 format:
With Template Story
Without template story
This example doesn’t have a templateStory, but still separates the render JSX into a normal looking React component function so that it will pass eslint
This would be a good thing to add to the docs, or to automatically do on v7 upgrade. Just changing the import line allowed it to work without changing the rest of the stories file.
I’m facing the same issue, but on Angular.
@suparngp Thanks so much for this question as it help me resolve an issue for dynamic assign of story args 🎉
You can find detailed implementation here: https://stackoverflow.com/questions/63708208/how-to-dynamically-mutate-args-in-storybook-v6-from-the-components-action/67424836#67424836
Hi everyone! Seems like there hasn’t been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don’t have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!
Hi everyone! Seems like there hasn’t been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don’t have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!
I think I now understand the root cause of this issue.
I believe we decorate the stories lazily. So when the component which is using
useArgsis wrapped in another function, only the top level function is decorated. So if I useuseArgsin the wrapping functionMyStory, it works because it is decorated. But the internal componentSmallis not and thus it throws this error. Just usingSmallworks because it is also decorated automatically when stories are added.That also explains why the calls happen in different order I think.
Recursively decorating the components sounds weird though, so I’d understand if this is not something that we can support. But if there is a way to create a decorated component manually, then probably my use case will be solved. For example, if I could do something like this:
These are just guesses though because I am way to excited to migrate to v6 and trying to figure out some workaround. 😸
What’s strange about it is that my changes worked… then after a refresh in browser the error appeared. Wouldn’t have suggested to follow the code if it had made the error. It’s definitely Storybook itself which is throwing the error. I’m going to open a fresh issue for this as we’re clearly off the path of the OP’s issue.
This has been marked as “has workaround”, but what is the workaround? The problem still exists and I’m not seeing a working alternative in the thread.
If
updateArgsis not intended to be used within story functions, and only within decorators, could the docs be updated? There are widespread examples of using things like an onclick or onchange to trigger an updateArgs. Which sometimes works in simple cases but not like in the example presented in the original issue where you are nesting templates.Note: I’m also dealing with web components, and Lit. In one particular case, the error was triggering with use of the
repeatdirective. Usingmapinstead was a workaround that stopped the error.I’ve the same problem as @ArkenStorm
I’m using storybook/vue3 and the
useArgshook seems to be react-only. I hope there’s a way to (programmatically) change args for vue as well@anthonyma94
import { useArgs } from '@storybook/client-api';in v6 this is still supportedI’m on Storybook v6, and the client-api library is deprecated. I’m trying to use the @storybook/api library instead, but it’s throwing
TypeError: Cannot read properties of undefined (reading 'getCurrentStoryData')when I useuseArgs()inside of a template:can anyone help me out?
If I pass
updateArgsas a prop down the tree, I think it updates the args of the component whereuseArgswas invoked which makes sense. For now, I think I ll just wrap up the migration with theuseStateso that at least I am on v6. May be this is something that you might wish to consider for the next releases. I ll keep an eye.