Add Conditional Logic to Storybook Compontent Data Fetching
Using conditional logic to deal with fetch requests.
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the Storybook for React Apps course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Storybook for React Apps, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

[00:00 - 00:08] In the previous lesson, we learned how to apply the container pattern to our components and avoid doing data fetching in Storybook. But what if you don't want to refactor every single one of your components?
[00:09 - 00:24] Another way to deal with data fetching is by using conditional logic. If we look at our original scenario and unfold it a little bit to see that there is a coding layer behind it, the component might be using a hook that calls an API and that API is the piece that connects to the backend.
[00:25 - 00:43] So what you can do here is to add local files that stub the data and add some conditional logic in the API so that if the code is running on Storybook, it will serve the data coming from the local files instead of reaching the backend. This way, the backend is reached in production but never reached while in Story book.
[00:44 - 00:58] So coming back to the restaurant's sexual example, let's undo the changes from the previous lesson because we don't need them anymore. So we don't need the stubs anymore, we're not using the container version of our component anymore and also the props are not passed and also the loading state is not there anymore.
[00:59 - 01:20] So when we check on Storybook, we should be able to see that the component is actually doing fetch requests as we access it. So if we analyze the implementation of the restaurant's section component, we see that it's calling a use fetch restaurant's hook, which then has access to an API and this is the part where actually the data is being fetched from.
[01:21 - 01:37] So if we check the API code, we see that there is a class for the restaurant's API, which is framework agnostic and that is essentially just fetching the data for the restaurants by ID and by category. If we want to apply some conditional logic to it, we need to know whether the application is running in Storybook or not.
[01:38 - 01:45] So if we go to the documentation, we can actually find that information ourselves. So there's a search docs feature over here. I will press command K to bring this comment palette here.
[01:46 - 01:52] And we can search for something like detect if running in Storybook. And we can see that there is an example for that.
[01:53 - 02:09] So Storybook is providing us a environment variable called Storybook, which if it's set, then it means that we're running in Storybook. So to make things simple, I already provide you a conditional logic version of the API, which is essentially pretty much the same API as before.
[02:10 - 02:25] But now we have a mock version, which is implementing the same interface so that every single method here is following the same signatures and the return types defined from the base API. And then when exporting the API, we check whether we are in a mocked environment.
[02:26 - 02:30] And if so, we provide the mocked restaurant's API. Otherwise, we provide the real API.
[02:31 - 02:42] And is mocked environment is a check that we're doing here at the top, whether we have the Storybook environment variable. Or also, if we are under a test environment, because this is also helpful for tests.
[02:43 - 02:54] So in order to apply this, all we have to do is go to the hooks file of which we are exporting the use fetch restaurants. And instead of using the API coming from index, we just change this to conditional logic.
[02:55 - 03:06] There is no other change necessary because the API will be changed depending on the environment. So when we're back to Storybook, we should see that when we switch stories, there's no data fetching anymore.
[03:07 - 03:09] And the rendering is instant. And there you go.
[03:10 - 03:15] This is pretty much how you can mock the data in the API level. So you don't have to make any changes to any components.
[03:16 - 03:20] And you make only one central change to the API. And this is great for TypeScript users.
[03:21 - 03:26] So if your project is using TypeScript, you can use a common interface in Type Script. As you can see, there's an base API.
[03:27 - 03:40] So that if you make any changes to, let's say, the return of this, if this is supposed to be a single value and not an array anymore. And TypeScript is going to detect that both in the mock API and also the production one, telling you that you should change the implementation because now they're wrong .
[03:41 - 03:45] And this is great because they're both in sync all the time. And are there any downsides to this approach?
[03:46 - 03:56] Of course, every approach has downsides and upsides. So depending on your code base, this approach might take quite some refactoring effort to apply because then you have to create the mocked versions of every single one of your APIs.
[03:57 - 04:07] And there's also the fact that you're making changes in your API code to satisfy some testing tools. And then that mock code might also end up being shipped to production, which adds unnecessary bundle size to the application.
[04:08 - 04:30] And also, if we go back to Storybook, we'd only have the default value because now it's a bit more difficult to reproduce the loading state of the component now that the change is in the API layer. There are other ways, however, to circumvent some of these downsides, such as introducing a new provider and changing implementation of the hooks to use an API, which instead of coming directly from an import, it will actually come from a context.
[04:31 - 04:44] And then you can provide a decorator in Storybook, just like we provided a decorator for themes, that for instance, we force Storybook to pass certain theme. We could have an API provider that we wrapped the app using the real API there.
[04:45 - 04:54] But in Storybook, we pass a different implementation to the APIs, allowing us to have a success state and error state and a loading state if we want it. And this pattern is known as the "penancy injection."
[04:55 - 05:10] I'm not going to get into detail, but you can read more about it in a blog post , which is linked in this lesson. Still, even if you were to do that, there's also the fact that now your component behaves differently in Storybook, so it doesn't actually do the network requests anymore because it just uses the mock data.
[05:11 - 05:28] So that means that you could potentially have a working component in Storybook while having a broken component in production, because, you know, there might be changes in the request headers, or maybe there's a typo in the URL, and you will not catch that in Storybook. In the next lesson, we'll see a different approach to dealing with data fetch ing that does not require touching your application code.
[05:29 - 05:29] So, I'll see you in the next one.