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

[Bug]: SB/React diffing is very slow #27374

Open
UltimateGG opened this issue May 27, 2024 · 1 comment · May be fixed by #27376
Open

[Bug]: SB/React diffing is very slow #27374

UltimateGG opened this issue May 27, 2024 · 1 comment · May be fixed by #27376

Comments

@UltimateGG
Copy link

UltimateGG commented May 27, 2024

Describe the bug

This is a pretty niche case, but it is with a popular library (tanstack/react-table), and shows something underlying must be wrong.

The reason I say it is the React diffing is because in the reproduction url, uncommenting line 139 (Removing table from being passed in props) fixes the issue. table is a huge object with lots of functions (you can console.log it to see). This does not happen in normal React so it is not a react-table issue.

I doubt it is only for react-table, but this is the use case I found the issue in. It most likely happens from large deep objects (Needs further narrowing/testing though).

Just noting it down: In the profiler I also see a function called "hookify" a lot which comes from storybook.

Reproduction link

https://stackblitz.com/edit/github-8gtech

Reproduction steps

  1. Visit the URL above
  2. Open the "Demo" story
  3. In the "Filter emails..." text field, type "abc" and observe the delay/freezing
  4. Scroll down to the "Fixed" story
  5. Repeat step 3 but on the "Fixed" story
  6. Observe the instant feedback

System

Storybook Environment Info:

  System:
    OS: Windows 10 10.0.19045
    CPU: (8) x64 Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz
  Binaries:
    Node: 20.11.0 - C:\Program Files\nodejs\node.EXE
    npm: 9.8.1 - C:\Program Files\nodejs\npm.CMD <----- active
    pnpm: 9.0.6 - ~\AppData\Roaming\npm\pnpm.CMD
  Browsers:
    Edge: Chromium (125.0.2535.67)
  npmPackages:
    @storybook/addon-essentials: ^8.0.10 => 8.0.10
    @storybook/addon-interactions: ^8.0.10 => 8.0.10
    @storybook/addon-links: ^8.0.10 => 8.0.10
    @storybook/blocks: ^8.0.10 => 8.0.10
    @storybook/react: ^8.0.10 => 8.0.10
    @storybook/react-vite: ^8.0.10 => 8.0.10
    eslint-plugin-storybook: ^0.8.0 => 0.8.0
    storybook: ^8.0.10 => 8.0.10
    storybook-dark-mode: ^4.0.1 => 4.0.1

Additional context

This is a very odd bug because you can remove the props: any from the Demo story, and the issue is fixed. I need to be able to pass props to this story though.

Tasks

No tasks being tracked yet.
@yannbf
Copy link
Member

yannbf commented May 27, 2024

Hey @UltimateGG thank you so much for this detailed report and repro! I'll add some detailed information to assist the maintainers/contributors when working on a solution for this.

I investigated and figured out the root cause. Storybook's addon-docs has a feature to show the rendered JSX element like so:
image

This is the line of code that gets executed in order to provide a stringified version of the React components, using react-element-to-jsx-string:

let string: string = toJSXString(simplifyNodeForStringify(child), opts as Options);

The problem is a combination of two things:

  1. Your component's props are too huge and complex to parse, and react-element-to-jsx-string has trouble do to that in a performant way.
  2. Storybook injects a jsxDecorator which, unless the user opts out of it (I'll get to it later), will execute the "stringification" of the rendered component, in every render cycle, as can be seen here:
    const rendered = renderJsx(sourceJsx, options);

It's quite unfortunate because react-element-to-jsx-string is being executed even if you're not using the component in a Storybook docs page.

To circumvent the issue, for now, you can opt-out of the jsxDecorator by adding the following parameter to your story (or to the default export):

Demo.parameters = {
  docs: {
    source: {
      type: 'code'
    }
  }
}

This should make sure the stringification won't happen and your interacting with your component will become instant again.

@yannbf yannbf linked a pull request May 27, 2024 that will close this issue
8 tasks
@shilman shilman added the sev:S3 label May 27, 2024
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.

3 participants