storybookjs / storybook

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

[Bug]: "useArgs" hook updates wrong story when rendered in "Stories" block #28333

Open brycenaddison opened 2 weeks ago

brycenaddison commented 2 weeks ago

Describe the bug

When writing a story for a controlled component, one should expect the useArgs hook to update the args being passed to the story it is being called in. However, when used inside a "Stories" block, it updates the page's primary story instead of itself. This isn't an issue when using a "Canvas" block or any other block that selects a specific story. I'm sure this could be user error but I don't see why there would then be a discrepancy between the functionality between the "Stories" block and an individual "Story" block.

Reproduction link

https://stackblitz.com/edit/github-n2sxrc?file=src%2Fstories%2FInput.tsx

Reproduction steps

  1. Go to the "Input" docs in Storybook.
  2. Attempt to edit one of the stories under the "Stories" header.
  3. Notice that value of top story is changing, instead of the story being edited.

System

Storybook Environment Info:

  System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 18.20.3 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.2.3 - /usr/local/bin/npm <----- active
    pnpm: 8.15.6 - /usr/local/bin/pnpm

Additional context

No response

brycenaddison commented 1 week ago

For anyone having a similar issue, I was able to work around it by making a custom block to use instead of Stories.

/** A block for showing a list of stories. */
export const MyStories = ({
  of,
  exclude = ['Primary'],
}) => {
  const resolvedOf = useOf(of ?? 'meta', ['meta']);
  const moduleExports = resolvedOf.csfFile.moduleExports;
  const exportsOrder = moduleExports.__namedExportsOrder;

  return (
    <>
      {exportsOrder
        .filter((name) => !exclude.includes(name))
        .map((name) => (
          // Title, description, and canvas blocks
          <MyStory key={name} of={moduleExports[name]} />
        ))}
    </>
  );
};