Open Key5n opened 9 months ago
@Key5n thanks for filing. what's happening is that we have a kind of special case for the "primary" (aka first) story in the list. it shows up twice on the page, and the controls only control the top instance. the next instance always displays the initial args. the way we handle the primary story is a little hacky, but as a workaround, i'd recommend writing controlled stories with a useState
hook instead. @tmeasday do you have any other suggestions?
@shilman
Thank you for replying.
Although you suggest using useState
, controlled component implemented by useState
has a problem.
The problem is that component with useState
cannot be controlled by Controls (I refer to the panel at the bottom of the screen) in component-detailed screen.
When I click the checkbox with useState
, the value in Controls doesn’t change.
This isn’t due to storybook, but the relationship between useState
and React’s props.
You can see this from my video as well.
If you know how to control components with useState
and avoid this problem, let me know.
This problem doesn’t apply to components with useArgs
, so I prefer useArgs
.
OK, so it's clear that you want the controls state to sync with the component's state, which makes sense. So useArgs
is the right thing to use.
I think probably what's off here is that you can affect the args in the second "static" version of the story, which doesn't respond to args changes. Perhaps we should add some behaviour to useArgs
so that the update function is a no-op inside such stories. I don't really remember if that'd be easy or hard to do.
WDYT @JReinhold?
Alternatively we could give you a way of opting out of the "static"-ness of the second rendering of the story (or a way to remove it entirely).
Perhaps we should add some behaviour to useArgs so that the update function is a no-op inside such stories. I don't really remember if that'd be easy or hard to do.
Sorry I don't quite understand what you're suggesting here @tmeasday
@Key5n if you configure your own autodocs page by setting parameters.docs.page
(globally in preview.js
) you have two options:
use the includePrimary
prop on the Stories
block:
// Replace your-framework with the framework you are using (e.g., react, vue3)
import { Preview } from '@storybook/your-framework';
import { Title, Subtitle, Description, Primary, Controls, Stories } from '@storybook/blocks';
const preview: Preview = {
parameters: {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
docs: {
page: () => (
<>
<Title />
<Subtitle />
<Description />
<Primary />
<Controls />
<Stories includePrimary={false} /> 👈👈👈👈👈
</>
),
},
},
};
export default preview;
However if you do this, the story above the Controls panel will be in sync with the story below - this is why this is disabled by default.
It's similar to the first workaround except you need to implement your own Stories
component. You can probably copy-paste the existing one from here, and then set the prop __forceInitialArgs={false}
.
Sorry I don't quite understand what you're suggesting here @tmeasday
I'm suggesting that if you are rendering a story with forceInitialArgs
set, then there is no point in the useArgs
hook having an updateArgs
callback that does anything, given the story will always render with the initial args. It'll just lead to weird behaviour like what we are seeing here.
I'm suggesting that if you are rendering a story with
forceInitialArgs
set, then there is no point in theuseArgs
hook having anupdateArgs
callback that does anything, given the story will always render with the initial args. It'll just lead to weird behaviour like what we are seeing here.
I see what you mean, so that would stop the primary, controllable story from reacting to changes in the static story.
I am running into a similar issue.
useArgs
to control the value
of a Radio buttonvalue
control to radio1
, the Radio buttons in the story re-render with radio1 selected. value
prop under Controls also changes to say radio2
.value
is set to radio2
initially, but when I try to click radio1
, nothing visibly changes.I noticed in the Docs view, the onChange event is actually being triggered with the new value (radio1), but seems like the re-render is not happening. Whereas in the individual story view, the onChange event is triggered with radio1
, and the story is re-rendered.
This is my controlled story:
export const Controlled: Story = {
args: {
groupLabel: 'Radio Group Label',
value: 'radio2',
},
render: function Render(args) {
const [{ value }, updateArgs] = useArgs()
function onChange(newValue: string) {
// Call the provided callback
// This is used for the Actions tab
args.onChange?.(newValue)
// Update the arg in Storybook
updateArgs({ value: newValue })
}
// Forward all args and overwrite onChange
return <RadioGroup {...args} value={value} onChange={onChange} />
},
}
What would you recommend as a workaround to get the Story working on the Docs view?
@JReinhold @kasperpeulen -- this is interesting, a use case very relevant to other discussions we've been having.
@kellyawang - would it be possible to put together a minimal reproduction of the behaviour you are describing? https://storybook.js.org/docs/contribute/how-to-reproduce
Describe the bug
See the video in this issue.
https://github.com/Key5n/storybook-useargs-bug/issues/1#issue-2059248804
When I click the first checkbox in Docs, changes take place in the checkbox. When I click the second checkbox, changes doesn't take place in the second checkbox, but in the first checkbox (moreover only once).
This bug happens only in Docs. I couldn't why this bug happens.
I show the case using
useState
for controlled component as well. The aim of this is to show you that this bug doesn't occur usinguseState
in Docs.How can I solve this bug?
If this bug has already been reported, I apologize.
To Reproduce
npm install
npm run storybook
System