Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error in jsxDecorator if a story function triggers Suspense #17839

Closed
redbugz opened this issue Mar 31, 2022 · 1 comment · Fixed by #17915
Closed

Error in jsxDecorator if a story function triggers Suspense #17839

redbugz opened this issue Mar 31, 2022 · 1 comment · Fixed by #17915

Comments

@redbugz
Copy link
Contributor

redbugz commented Mar 31, 2022

Describe the bug
If a story function triggers suspense then the story errors with "Rendered more hooks than during the previous render."

To Reproduce
I have created a repro using the cra template. I will upload it and post it shortly once I clean it up a bit.

System

Environment Info:

  System:
    OS: macOS 12.2.1
    CPU: (10) x64 Apple M1 Pro
  Binaries:
    Node: 14.18.3 - ~/.nvm/versions/node/v14.18.3/bin/node
    Yarn: 1.22.17 - ~/.nvm/versions/node/v14.18.3/bin/yarn
    npm: 6.14.15 - ~/.nvm/versions/node/v14.18.3/bin/npm
  Browsers:
    Chrome: 99.0.4844.74
    Edge: 99.0.1150.55
    Firefox: 98.0.1
    Safari: 15.3
  npmPackages:
    @storybook/addon-a11y: ~6.4.0 => 6.4.19 
    @storybook/addon-actions: ~6.4.0 => 6.4.19 
    @storybook/addon-console: ^1.2.3 => 1.2.3 
    @storybook/addon-controls: ~6.4.0 => 6.4.19 
    @storybook/addon-docs: ~6.4.0 => 6.4.19 
    @storybook/addon-essentials: ~6.4.0 => 6.4.19 
    @storybook/addon-knobs: ~6.4.0 => 6.4.0 
    @storybook/addon-links: ~6.4.0 => 6.4.19 
    @storybook/addon-storysource: ~6.4.0 => 6.4.19 
    @storybook/addon-toolbars: ~6.4.0 => 6.4.19 
    @storybook/addon-viewport: ~6.4.0 => 6.4.19 
    @storybook/addons: ~6.4.0 => 6.4.19 
    @storybook/api: ~6.4.0 => 6.4.19 
    @storybook/components: ~6.4.0 => 6.4.19 
    @storybook/react: ~6.4.0 => 6.4.19 
    @storybook/theming: ~6.4.0 => 6.4.19 

Additional context
Originally I thought this was related to #15223 but it appears to be a separate issue that results in the same error message.

We use a third party hook that triggers suspense while loading some data. If a story function uses that hook, then you get this error. Some debugging showed it failing on this code in jsxDecorator:

export var jsxDecorator = function jsxDecorator(storyFn, context) {
  var _context$parameters$d2, _context$parameters$d3;

  var channel = addons.getChannel();
  var skip = skipJsxRender(context);
  var story = storyFn(); // <<<--- it fails here since the storyFn throws a promise to trigger suspense
  var jsx = '';
  useEffect(function () {
    if (!skip) channel.emit(SNIPPET_RENDERED, (context || {}).id, jsx);
  }); // We only need to render JSX if the source block is actually going to
  // consume it. Otherwise it's just slowing us down.

  if (skip) {
    return story;
  }

Since the storyFn throws a promise to trigger suspense (even though I have a decorator setup with Suspense) it causes the useEffect to never be called until the Suspense is resolved, then it rerenders and storyFn renders fine, but now there is an extra useEffect call so you get the "Rendered more hooks than during the previous render.". It essentially makes the useEffect conditional based on the status of the Suspense.
I don't see any reason the storyFn has to be called above the useEffect, so I plan to submit a PR to move the storyFn call below the useEffect call. I manually made this change in node_modules in my local storybook and that fixed the problem for these stories that use this hook.

it works fine if the hook is called by a component in the story, it only fails if the story function itself uses the hook directly.

redbugz added a commit to redbugz/storybook that referenced this issue Apr 8, 2022
If a story function triggers Suspense by throwing a promise liike
some third party hooks do, the story will fail to render
because the useEffect is skipped the first time and then
run the second time, resulting in the
"Rendered more hooks than during the previous render." error
This runs the story function after the useEffect hook so the same number of hooks
are run whether it triggers suspense or not, and in keeping
with the guidelines on not conditionally running hooks
@shilman
Copy link
Member

shilman commented Jul 2, 2022

Crikey!! I just released https://github.com/storybookjs/storybook/releases/tag/v7.0.0-alpha.10 containing PR #17915 that references this issue. Upgrade today to the @future NPM tag to try it out!

npx sb upgrade --prerelease

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants