Adding PageTemplate and Redux support to Storybook
Let's add the page templates to Storybook.
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:15] Before jumping into page components, let's first check a component that is present at every page. It's called a page template. It's quite common to have page wrappers that handle things like navigation, state management, and other functionality, while also displaying page content under different layout settings.
[00:16 - 01:10] So first of all, let's open a new terminal instance and get to know a bit more about MuDrop. Let's start the application by running YarnStart. And in the app, you'll see that every page might have a header and a footer. So the home page, if I scroll, the header goes away. If I go into the restaurant DTO page, because the header, it contains a shopping cart button. And it's important to know the many items that you order and the total that they amount to. If you scroll the header, it should be present. And the same goes for the footer. But if you go to the checkout page, the footer is gone and the header stays with no navigation items and no shopping cart. So having all of these business roles and variants of a page template, it seems quite important to have a single place where you can document all of them and refer to. And that's basically Storybook. So let's jump back to the code and understand what's going on. So under source and templates, we see the page template element.
[01:11 - 03:31] And that's basically a template that contains a type and children. And depending on the type, it could be a basic sticky header or just default, it will render different things. And if you go into the app TSX, you will see app routes. And that's basically every single page of these application and their routes. And each one of these pages, if you go to the home page, for instance, you will see it's wrapping its contents with a page template. And for instance, the checkout page, it's using a page template, but with the type basic. So let's go ahead and add the page templates to Storybook. You're not a drill, we basically need to create a new file. So let's call this page template dot stories. t is X. And I'm just gonna paste the entire template here , just to make things simpler. You already know what's going on, right? So we essentially have a meta with a title of templates page template. And that's just a follow the folder structure. We have our master template over here receiving arcs. And we have our stories. Also, I created a dummy component, which is just a very simple component, just to kind of like add some content to the page. And that receives children and has some padding around. This helps us kind of document the story so that people reading the story know what's going on. So the default one has a default template with scrollable header and navigation items, plus a footer. So once we're back to Storybook, if you don't see the new story over here, you just need to refresh. And then you'll see there's a template section now with the page template. Once we access the story, ah, something is broken. Well, if we inspect the element and we notice the error, it says could not find react to Redux context value. And in the console, we see that the error is happening at the header components under the page template. And that makes sense, because the header component actually needs information from Redux. So that under the restaurant detail page, you can get information like what is it that you're ordering. So the header component is a connected component from Redux. And it just needs support in Storybook. And I'm pretty sure you know by now what we have to do, which is going to the app implementation and see what's actually being used to add support to Redux. And over here, we see that there is a store provider, which is receiving an implementation of the store. So the store provider comes from React Redux and the store comes from the app state folder. So what we can do is we can basically copy these imports and go to our store book folder, because you know, we have to create a new decorator.
[03:32 - 04:21] So over here, we essentially paste the new imports. And we fix this one because now over here, we need to access the app state. So that's one level above under source. And we create a new decorator. So we can call this, for instance, with store, which is a type of decorator function that receives a story, a fan. And it will return essentially a store provider that receives a store that we have from our imports. And it will render the story function. Because we want every story to have supports to Redux, we just need to add that to the global decorators. So once we're back to Storybook, our story renders correctly. And there you go, you've got the page template in Storybook, which is great. So let's go back to Storybook and add new stories to the other variants.
[04:22 - 04:59] So we basically have the variants of type default sticky header and basic. So I 'm just going to paste the stories over here. And that's essentially just a copy base of them, plus some different arcs. So the sticky header has a sticky header type and some text, which is just saying this is a sticky header. And the basic one contains a type basic, which also just says this is a simple template that doesn't have footer. And when we check Storybook, we see that we have these new stories. So the sticky header, and if we try scrolling, then the header stays. And the basic doesn't have a footer and navigation items. There's one small detail, which is kind of annoying.
[05:00 - 06:46] If you notice, Storybook is adding a 16 pixel padding around every story. And that doesn't really look that great for pages. Well, we learned in a previous lesson that you can basically change the layout of Storybook by passing a parameter. And because we want every story to have this different, we pass in the meta level. So you can call this layout and full screen. And that's essentially going to change the way the storybook renders the template by removing the padding. And now we see that the page is taking the full container size. And this is great. Now any developer, when checking Storybook, they will see all of the available types of the page template so that they can choose whenever they're developing a new page in the application. However, there is one particular limitation to what we did. If we go to our decorators file, we will see that with the width store, every component has support for Redux. But they're always using the same store, which is defined with the data from a combination of the default reducers. But if we analyze in the application, we have a different state of the page template that actually contains some data , which changes the visual state of the shopping cart. And also there's a sidebar, which also has different visual state. So it will be really great if there's a way to actually set initial states per story, so that we can simulate those visual states in Storybook. And that's definitely possible. So let's go back to the decorators. And let's change the implementation in a way that we can actually configure the sort that we want before passing it down to the provider. So there's a couple of things that we have to do. The first one is we need to import a function from @ Redex.js/toket, which is the library we've been used in this project. And it's called configure store. The other thing is we don't want the default store from our app state anymore.
[06:47 - 07:41] We actually want the root reducer. And then we are going to use a combination of these two things under our width store decorator to create a store on the fly. So let's call this const store equals configure store. And then this receives an object of options of which you can pass a reducer. And that's going to be our root reducer. And then optionally, you can pass a preloaded state. And the preloaded state, let's just put an empty object for now. It's the initial state that you want to overwrite. And in the previous lesson, we learned that you can use the context and you can pass parameters from it so that you can pass any data that you want. So over here, let's use that as well. So let's destruct your context to get access to parameters. And over here, we're going to access in a possible initial state that we're going to define in our stories.
[07:42 - 07:56] And because the parameters are pretty much flexible, we can call whatever we want. So let's call this parameters. And then every story, let's say that we want to define in an initial state, we 're going to call store. And this might be undefined. So let's just add a optional chain operator over here.
[07:57 - 08:44] Let's say this is called initial state. So once we save this, essentially, there should be no difference in the functionality in our stories. So when we're back to storybook , things should work just the same. However, now we're able to create a new variant of our component that we can pass the initial data from. So let's copy the default story. And let's also maybe remove the arcs. And let's call this with items in the cart. And then with items in the cart, it 's going to have a parameter of, and we just defined, it's going to be called store. And inside of it, it's initial state. So the structure that the header needs, it's called cart. And then inside of it, it has a property called items. And then we can pass some stub data for the cart items.
[08:45 - 09:21] And unfortunately, we have that information over here. So we can import our stub data from stub slash cart items. And it's called cart items. So we basically get this over here, and we pass as items. And once we're back to storebook, we see that there's a new story called with items in the cart. When we access it, if it's not working well, you might need to refresh, because likely there's a cash issue. But over here, now you see that the template is working correctly with some initial state over there. So if we switch stories, we see that every variant of our page template is defined.
[09:22 - 09:46] And that's just great. Now every component in our storebook has redoque support . And we can tinker with the initial state of our components if we want it. And instead of creating our own the creators, we could have used a redoque storebook atom from the community. But by creating our own, not only it was a great exercise, but now we have more control over what it does. And you can also apply this knowledge to support any similar technology in your projects.
[09:47 - 09:50] So now we're pretty much ready to add full pages into storybooks. So I'll see you in the next one.