storybookjs / storybook

Storybook is the industry standard workshop for building, documenting, and testing UI components in isolation
https://storybook.js.org
MIT License
84.21k stars 9.26k forks source link

[Bug]: array or object with JSX elements in context causes Storybook to hang indefinitely #19575

Open alicnik opened 1 year ago

alicnik commented 1 year ago

Describe the bug

Providing an array of JSX elements, or an object containing JSX elements, as the value in a context provider causes Storybook to hang indefinitely. The UI may load but it cannot be interacted with once you click on the story with the context issue.

This only happens with arrays/objects. Passing a JSX element as the value in context works fine.

Example code of adding context in a story (with an array):

const Template = (args) => (
  <FooContext.Provider value={[<div>Hi</div>]}>
    <FooComponent {...args} />
  </FooContext.Provider>
);

This also happens if the context is placed in decorators, e.g. (with an object):

export default {
  ...csf,
  decorators: [
    (Story) => (
      <FooContext.Provider value={{ test: <div>Hi</div> }}>
        <FooComponent />
      </FooContext.Provider>
    )
  ]
}

One solution is to use the storybook-react-context add-on, however if there is something I have missed that is causing this issue I would welcome guidance on solving it without using an add-on.

To Reproduce

https://github.com/alicnik/storybook-jsx-array-context-bug

System

System:
    OS: macOS 12.6
    CPU: (8) x64 Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
  Binaries:
    Node: 16.18.0 - /usr/local/bin/node
    Yarn: 3.2.4 - /usr/local/bin/yarn
    npm: 8.19.2 - /usr/local/bin/npm
  Browsers:
    Chrome: 106.0.5249.119
    Firefox: 102.0.1
    Safari: 16.0
  npmPackages:
    @storybook/addon-docs: ^7.0.0-alpha.40 => 7.0.0-alpha.40 
    @storybook/addon-essentials: ^7.0.0-alpha.40 => 7.0.0-alpha.40 
    @storybook/addon-interactions: ^7.0.0-alpha.40 => 7.0.0-alpha.40 
    @storybook/addon-links: ^7.0.0-alpha.40 => 7.0.0-alpha.40 
    @storybook/react: ^7.0.0-alpha.40 => 7.0.0-alpha.40 
    @storybook/react-webpack5: ^7.0.0-alpha.40 => 7.0.0-alpha.40 
    @storybook/testing-library: ^0.0.13 => 0.0.13

Additional context

No response

burdisal commented 1 year ago

I am also running into this issue, passing an array of JSX elements as a prop to a component in Storybook. The following works well in a fresh Create React App, but hangs in Storybook, locking up my browser when I try to click any of the buttons.

One of my projects is not able to update Storybook because of #17413, and this component works without issue in that project (Storybook 6.3.12).

The only workaround I have found is sending the array of JSX as children, since sending it as a prop consistently causes Storybook to hang.

This issue looks like it also may be related to #17877.

My Component:

export default function Slideshow({ pages, page }) {
  return <div>{pages[page]}</div>;
}

And in my Storybook file:

const Template = (args) => {
  const [page, setPage] = useState(0);
  return (
    <Slideshow
      {...args}
      page={page}
      pages={[
        <button onClick={() => setPage(1)}>Go to page 2</button>,
        <button onClick={() => setPage(2)}>Go to Page 3</button>,
        <div>Page Three</div>,
      ]}
    />
  );
};

System

System:
  OS: MacOS 12.5.1
  CPU: 2.3 GHz 8-Core Intel Core i9
Binaries:
  Node: 16.1.9
  NPM: 7.24.2
Browsers:
  Firefox: 105.0.3
  Chrome: 106.0.5249.119
  Safari: 16.0
NPM Packages:
    "@storybook/addon-actions": "^6.5.12",
    "@storybook/addon-essentials": "^6.5.12",
    "@storybook/addon-interactions": "^6.5.12",
    "@storybook/addon-links": "^6.5.12",
    "@storybook/builder-webpack5": "^6.5.12",
    "@storybook/manager-webpack5": "^6.5.12",
    "@storybook/node-logger": "^6.5.12",
    "@storybook/preset-create-react-app": "^4.1.2",
    "@storybook/react": "^6.5.12",
    "@storybook/testing-library": "^0.0.13",
alicnik commented 1 year ago

After some digging, it seems to be the same issue at heart as https://github.com/storybookjs/storybook/issues/12747. @burdisal perhaps the workaround there will work for you? Adding this to parameters in the story solved the issue for me:

docs: {
  source: { type: 'code' }
}
burdisal commented 1 year ago

@alicnik Thanks for the comment. Adding this does indeed solve this on my end.

kostia-official commented 1 year ago

@alicnik thanks, added to global parameters in preview.js and it worked

export const parameters = {
  docs: { source: { type: 'code' } },
};
thexpand commented 1 year ago

Setting the parameters.docs.source.type to code did the trick for me, but I can't understand why. I found this in the API docs: https://storybook.js.org/docs/react/api/doc-block-source#type

By I still don't understand what's the difference between code and dynamic. Anyone care to explain?

tmeasday commented 1 year ago

The explanation for this issue is that react-element-to-jsx-string doesn't like it when you pass props that contain rendered elements.

See https://github.com/algolia/react-element-to-jsx-string/issues/681

We already filter out pure elements and arrays that contain elements (https://github.com/storybookjs/storybook/issues/17482). It seems we still have an issue with objects that contain elements.

It sounds like maybe pinning the version of react-element-to-jsx-string to 14.3.2 may fix the issue. Why don't we just do that if it is unmaintained @shilman @IanVS ?

emlai commented 11 months ago

The element doesn't have to be in a context to reproduce. See e.g. duplicate #17720.

tmeasday commented 11 months ago

Can folks who are seeing this try pinning the version of react-element-to-jsx-string to see if it indeed does help? In package.json:

npm:

"overrides": {
   "react-element-to-jsx-string": "14.3.2"
}

yarn:

"resolutions": {
   "react-element-to-jsx-string": "14.3.2"
}
emlai commented 11 months ago

@tmeasday Thanks, that seems to have fixed the issue.

jonathan-chin commented 9 months ago

@tmeasday this fixed it for me as well!

tmeasday commented 9 months ago

@shilman shall we pin the version then?

shilman commented 9 months ago

@tmeasday I tried to reproduce here but couldn't https://github.com/storybookjs/storybook/pull/25312

tmeasday commented 9 months ago

Hmm, yeah I am not seeing it in your example either. Can someone provide a working reproduction in 7.x?

jleider commented 5 months ago

This also affects v8.1.0

tmeasday commented 5 months ago

@jleider can you (a) provide a reproduction if possible? (b) confirm if pinning the version resolves it?

jleider commented 5 months ago

@jleider can you (a) provide a reproduction if possible? (b) confirm if pinning the version resolves it?

@tmeasday

a) Its in a private repo and I don't have a simple reproduction case at this time. Although, I can see if we can make one for you.

b) Yes, the pinning of the version resolves it. We had previously had it pinned and I was hoping that the issue was resolved when upgrading storybook from v7 to v8 but the issue is still present.

SuttonKyle commented 4 months ago

@jleider can you (a) provide a reproduction if possible? (b) confirm if pinning the version resolves it?

Hi @tmeasday, I've managed to get a minimal working reproduction for the bug in Storybook 8, which you can see here: https://github.com/SuttonKyle/storybook-bug-repro

In this case, the response is very slow the first time you change the variant prop, and the second time you try to do so it freezes entirely. It seems to have to do with the fact that we have a jsx element nested within an object passed as props. If we do not pass args to the render function, the freeze does not occur. Please let me know if you have any questions or there's anything I can clarify for you! Thank you!

tmeasday commented 4 months ago

Thank you for the reproduction @SuttonKyle. Can confirm both the bug and that pinning the version fixes it.

@shilman I think we should change the version of react-element-to-jsx-string we depend on. Do you agree?

shilman commented 4 months ago

@tmeasday I'm OK with that. Perhaps we can handle it properly later this year.

aczekajski commented 2 weeks ago

Btw my project is using Storybook 6.5.9 which uses react-element-to-jsx-string in version 14.3.4 and it also causes this problem.

Is there a plan to patch this problem in Storybook v6 as well?