-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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]: React component seems to be mounted twice when a story render function uses the args parameter #23921
Comments
I have run into this issue as well. It looks like the function arguments don't even need to be used, by the fact that they are defined on the function is enough to cause it to render twice. I have found a workaround, if you put all of the function arguments into a single rest argument, the story appears to only render once. It's not pretty, but it works for me. This causes the story to render twice:
But this will cause the story to only render once (as expected):
|
Confirm that args causes mounting twice. And each time args - same object. let argsMemorized: object | undefined = undefined
const CheckedIcon: React.FC = (args) => {
if (argsMemorized === undefined) {
console.log("no argsMemorized")
argsMemorized = args
}
useEffect(() => {
console.log("CheckedIcon mounted args", args)
console.log(
"CheckedIcon mounted args === argsMemorized",
args === argsMemorized
)
return () => {
console.log("CheckedIcon unmounted")
}
}, [args])
return <Renderer src={checkedIcon.src} />
} Output:
And confirm, this workaround works. |
I plan to take a look at this. |
@mirobossert I suspect it's react in strict-mode that's acting differently based on wether |
I've investigated this and concluded that the source of this bug is
this isn't the case @ndelangen, we're not rendering in strict mode, that is something the user explicitly adds to the story when needed. The double rendering happens because of this logic: storybook/code/renderers/react/src/docs/jsxDecorator.tsx Lines 256 to 259 in 5788560
Basically, when we want to exclude decorators from the source generation (for docs), we first execute the (Interestingly this doesn't just impact the initial rendering - as in the reproduction above, when you click the button to flip the state, that also logs twice, even though only one is rendered. My guess is that executing the same instance of a React component multiple times isn't really compatible with React.) The reason this seems related to args, is because when a story has args it gets the storybook/code/renderers/react/src/docs/jsxDecorator.tsx Lines 197 to 209 in 5788560
I've confirmed this by setting Finally, setting The logic that executes @shilman @tmeasday do you have any good ideas for how to fix this, beyond completely reworking our source-generation logic? |
Great work figuring that out @JReinhold! I want to say I remember something like this happening once before and us reordering decorators in order to not have to enable |
@tmeasday here's the paper trail I've found:
I find this specific change by @tmeasday interesting: Where we don't execute |
@JReinhold I think that change doesn't quite do that, I think it actually always calls Thank you for the leg work so I think the history here is:
I wonder if ultimately we need a different approach for A hacky solution we had considered was some mechanism to "force" the source decorator to be the last (or would you call it first) one, somehow. |
I can see that working, but do we then put it as the innermost decorator to only show the pure story, or should it still encapsulate the user-defined decorators in the project, meta and story-level? I'm unsure what the desired behavior is. Perhaps we acknowledge that if you put something in a decorator, you don't want it in the source view - if you want a wrapper displayed in the source view, it must go in |
I think that sounds right |
Describe the bug
When using the
args
parameter in the render function of a Storybook story, the React component appears to be mounted twice. This behavior is causing issues, especially when using a custom hook directly in the story.To Reproduce
Working
andNot Working
and observe the browser console to see the different behaviour of the two stories.https://stackblitz.com/edit/github-56csk3?file=stories%2FButton.stories.tsx
System
Additional context
I understand that the observed behavior might be intentional or could potentially be influenced by the implementation of the custom hook. While I've tried to isolate the issue to the best of my ability, it's possible that there are factors I'm not aware of that could contribute to this behaviour.
Any assistance, guidance, or ideas on how to approach this issue would be highly valued. Thank you in advance for your help.
The text was updated successfully, but these errors were encountered: