Closed tmeasday closed 4 years ago
This is still an issue, stalebot.
My use-case is preloading all the fonts before rendering the stories so that snapshots always have the correct fonts loaded.
So we've thrashed this out a bit and concluded that allowing arbitrary async-ness in stories and decorators isn't a great idea. Here's why:
If any story or decorator can be async, then all decorators have to be async. This is problematic in particular for addons (at lot of which may not be!)
In React, we can't have the decoratoredStoryFn
be async and still render it as a component. So given 1. this would mean you couldn't use hooks in stories or decorators, which would be a problem for a lot of users.
Given that we've been considering an alternate way of introducing async-ness to stories: Loaders. Here's a sketch of an API:
// A CSF file
export default {
title: 'MyComponent',
loaders: [async () => ({ Component: await import('./MyComponent') })],
}
export const MyStory = (args, { Component }) => <Component {...args} />;
The idea is:
For the above example we could simplify things with a global loader, which is potentially available by default (just an idea):
// preview.js
export const loaders = [async ({ componentPath }) => ({ Component: await import(componentPath)],
// A CSF file
export default {
title: 'MyComponent',
componentPath: './MyComponent',
}
export const MyStory = (args, { Component }) => <Component {...args} />;
@tmeasday this is genius ❤️
I have a different but related use case that I don't think this would resolve.
We use https://www.npmjs.com/package/storybook-react-router to configure routes, where params are used by hooks within containers that we want to test. E.g.,
// Some set-up hook
async init = () => {
const item = await db.createItem();
return item.id;
}
export default {
title: 'Invitations',
decorators: [
new StoryRouter(null, {
initialEntries: [`/item/${itemId}`] // Somehow access async set-up.
})
]
};
const Test = () => {
const { itemId } = useParams();
const item = db.getItem(itemId);
return <div>{item}</div>
};
export const withItem = () => {
return (
<Switch>
<Route path='/item/:itemId' component={Test} />
</Switch>
);
};
Here, itemId
is the ID of an object that should be asynchronously created (for the test) before the component navigates to the route. Do you have a suggestion for this use case?
@richburdon could your async decorator not be run in a loader?
Huzzah!! I just released https://github.com/storybookjs/storybook/releases/tag/v6.1.0-alpha.23 containing PR #12699 that references this issue. Upgrade today to try it out!
You can find this prerelease on the @next
NPM tag.
Closing this issue. Please re-open if you think there's still more to do.
Just confirming @shilman that I'm looking at the new code properly. What I was originally thinking (and was not working properly):
export const getActiveContext = () => {
return Promise.resolve({ foo: bar }); // NOTE: this would call some long running api to bring back data before resolving
}
const withContextProvider = async (Story, storyContext) => {
const activeContext = await getActiveContext(storyContext)
return (
<StatefulProvider value={activeContext}>
<Story {...storyContext} />
</StatefulProvider>
)
}
export const decorators = [
withContextProvider,
]
but once moving to the new v6.1.0-alpha.23, I am using the following:
export const loaders = [
async () => ({
activeContext: await Promise.resolve({ foo: bar }),
})
]
const withContextProvider = (Story, {
loaded: {
activeContext
}
}) => {
return (
<StatefulProvider value={activeContext}>
<Story {...storyContext} />
</StatefulProvider>
)
}
export const decorators = [
withContextProvider,
]
This "seems to" be mostly working (which is awesome), but just want to confirm I'm using the new async loaders
properly??
LGTM @agrohs 👍
Had everything working properly yesterday on alpha 23 and woke up this morn to all broken. Tried going back in commits and even everything running against 6.0.26 stable seems to be broken. Getting a very strange set of errors related to react hooks, but what's really bizarre about them is that the webpack'd debug stack seems to be showing URLs similar to: webpack://storybook_ui_dll//Users/shilman/projects/baseline/storybook/node_modules/react/cjs/react.development.js?:1439
Any ideas what may have happened @shilman
This looks potentially related to the fact that storybook does not have pinned versions in its package.json AND a major new update of React went live yesterday (6.14.0) that has broken many projects across the web today: https://github.com/facebook/react/blob/master/CHANGELOG.md.
A similar issue of a dependency of a dependency wreaking havoc on a project happened several months back w/ moment.js
b/c their versions were not pinned.
I was able to get this back resolved by adding a resolutions node in our projects package.json
to ensure we don't use the upgraded version until working properly w all third parties:
"resolutions": {
"**/react": "16.13.1",
"**/react-dom": "16.13.1",
"**/react-is": "16.13.1"
}
This will likely kill many hours for people today using storybook
if it hasn't already. Just sharing to try and save some other people headache - but wondering in general why storybook does not have pinned versions in its package file??
@agrohs opened a new issue to discuss #12787
Good golly!! I just released https://github.com/storybookjs/storybook/releases/tag/v6.1.0 containing PR #12699 that references this issue. Upgrade today to the @latest
NPM tag to try it out!
npx sb upgrade
is it possible to update the control panel argTypes in a loader ? i'm trying to asynchronously load in the optinos for a radio control
@jonnytest1 no, argTypes are statically defined
is it possible to update the control panel argTypes in a loader ? i'm trying to asynchronously load in the optinos for a radio control
@jonnytest1 A bit late to the party here but did you ever find a workaround for this problem? Facing a similar issue
is it possible to update the control panel argTypes in a loader ? i'm trying to asynchronously load in the optinos for a radio control
@jonnytest1 A bit late to the party here but did you ever find a workaround for this problem? Facing a similar issue
probably not possible 🤔 at the end i just used some examples
Consider supporting "async" stories in 6.0. What this may imply:
StoryRendered
event and should be OK.