storybook
storybook copied to clipboard
Controlled Input Loses Focus in Docs when Using useArgs Hook
Describe the bug
Using useArgs
hook to update a controlled text input React component works fine on the "Canvas" tab, but when using it in Docs mode, we encounter an issue where the input loses focus after every key press (hence, every time the args are updated). This makes interacting with it in Docs mode extremely difficult.
To Reproduce Steps to reproduce the behavior:
- Go to Docs tab
- Click on the story for
TextField
component - Attempt to type multiple characters into the input
- See error
Expected behavior The component should update the same within Docs as it does within the standard Canvas tab. The input should not lose focus when args are updated.
Screenshots If applicable, add screenshots to help explain your problem.
Code snippets Component:
import React from 'react';
import PropTypes from 'prop-types';
/**
* Wrapper around a text input
*/
export const TextField = ({ label = 'Foo', value = '', onChange }) => {
const handleChange = (event) => onChange?.(event.target.value);
return (
<React.Fragment>
<label>{label}</label>
<input type="text" value={value} onChange={handleChange} />
</React.Fragment>
);
};
TextField.propTypes = {
/**
* Text to use as a label
*/
label: PropTypes.string,
/**
* Value controlled externally to component
*/
value: PropTypes.string,
/**
* Change handler
*/
onChange: PropTypes.func,
};
TextField.defaultProps = {};
Story:
import React from 'react';
import { useArgs } from '@storybook/client-api';
import { TextField } from './TextField';
export default {
title: 'Controlled TextField',
component: TextField,
argTypes: {},
};
const Template = (args) => {
const [_args, updateArgs] = useArgs();
const handleChange = (value) => updateArgs({ value });
return <TextField {...args} onChange={handleChange} />;
};
export const Basic = Template.bind({});
Basic.args = {
value: 'foo',
label: 'Lorem ipsum',
};
System:
Please paste the results of npx -p @storybook/cli@next sb info
here.
Environment Info:
(node:73572) UnhandledPromiseRejectionWarning: TypeError: e.filter is not a function
at /Users/jcq/.npm/_npx/73241/lib/node_modules/@storybook/cli/node_modules/envinfo/dist/envinfo.js:1:73205
at async Promise.all (index 6)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:73572) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:73572) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
😅
I'm using @storybook/* 6.0.0-rc.14
with latest create-react-app
.
Additional context I've created a repo that demonstrates the issue
Is this still an issue in the latest release @jcq?
Is this still an issue in the latest release @jcq?
Yeah, this problem still exists :(
Possible dupe to https://github.com/storybookjs/storybook/issues/12255
Is this issue fixed? I'm experiencing it on 6.1.0-alpha.16
Nope, issue's still open
I think this is a dupe of #12255 -- if I add the decorator:
decorators: [(Story) => <Story />],
To your story, I see the same issue in canvas mode. If I change the decorator to:
decorators: [(Story) => Story()],
the issue goes away (in Canvas).
So I wonder if docs mode is rendering the story in such a way to trigger the same rendering issue.
I have a very similar problem with useEffect
triggering a onChange event, which in turn triggers updateArgs
, again. The values never change, but the component gets remounted. Also, it happens only in Docs mode, but not in Canvas mode. It seems to have the same cause.
This hasn't been fixed yet in 6.3.4. I think the reason is that updateArgs
triggers a re-render of the args table, which is in the same container as the story, causing that one to be re-rendered too, which causes the focus to be lost.
As proof I tried adding:
parameters: {
docs: {
inlineStories: false,
}
}
Then the story is rendered in an iframe, which makes the updateArgs
work, but then a change of the controls doesn't update the story.
The reason this doesn't happen in the canvas is because the addons-drawer is not in the same container as the story.
Still an issue in 6.3.12. Was able to fix it for my textfield component by adding an autoFocus, but that isn't an option for other components. Like @orjandesmet mentioned, it appears that after a change, the whole component re-renders, thus losing the focus. Seems like the change of the controls should not cause a full rerender, but rather only pass the new props down.
I've also noticed that this rendering/update pattern causes any component using the updateArgs to sometimes get unbearably slow causing the whole browser to lag. This is not surprising if the entire component is constantly re-rendering completely instead of just updating.
Still seeing this in 6.5.0-beta.7 any updates?
Hi there, I am facing the same issue in Docs section: component is unmounted / re-mounted after args update, which causes some components used in the decorator to be re-rendered. Does anyone have a workaround or is a fix planned? Thx to the team !
Ok, I took another look. You can observe this behaviour in the official-storybook
story core-rendering--args-change
if you:
a) make it the primary storybook for the component (remove the Counter
story)
b) turn off features.modernInlineRender
.
c) increment the first
arg in the controls panel.
As such, I think the issue is fixed by features.modernInlineRender
. Can the folks who are seeing the issue please try using that? It will be the default in 7.0 and we are unlikely to spend much time fixing any issues in the legacy inline render mechanism.
@tmeasday
Turning on features.modernInlineRender
in .storybook/main.ts
immediately solves this issue, as you predicted above:
module.exports = {
stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(ts|tsx)'],
addons: ['@storybook/preset-scss', '@storybook/addon-links', '@storybook/addon-essentials'],
features: {
modernInlineRender: true
}
Story is rendered as expected without any unmouting cycle at args update 👌
@tmeasday @fredericvilcot I've enabled modernInlineRender
however I'm still experiencing the issue in Storybook 6.5.9 (for React).
Having this issue too. Any idea if this is getting fixed in v7?
@jagoncalves14 I guess we need to confirm if it is still an issue with modernInlineRender
(which is the way it works in v7).
@oogali do you have a reproduction of the problem? (or @jagoncalves14?)
I was experiencing the same problem and modernInlineRender
fixed it for me (Storybook v6.5.16)
I upgraded the repro to 7.0 and the problem is fixed there. I would advise folks to either upgrade or use modernInlineRender
. Thanks!
I am using v7 and experiencing this problem, please advice.
"storybook": "^7.0.18",
support for modernInlineRender has been removed post v6 and v7 doesn't work.
@somandubey the "modern" rendering is the only option in SB7. If you are seeing an issue in SB7 I'd suggest opening a new ticket for it with a reproduction.
thanks @tmeasday for your quick response. it worked eventually. please ignore the request.