Storybook with React, Redux, and Material UI
Navigating the complexities of Storybook with React CRA, Redux, Material UI theming, proxies, and routing can be tricky.
Storybook is invaluable for developing and testing UI components in isolation, enabling rapid prototyping while forcing critical thinking to the API of your components and containers.
Initial Setup
Setting up Storybook with React is simple using the npx sb init
command. For example, to scaffold a Create React App with Storybook, simply execute the following:
npx create-react-app my-app
cd my-app
npx sb init
There’s been some issues recently with Storybook and CRA — you may have encountered babel errors after executing npx sb init
such as:
Error: Cannot find module ‘babel-loader’
Or, after adding babel loader:
ERROR in ./.storybook/storybook-init-framework-entry.js
Module not found: Error: You attempted to import …/my-app/node_modules/@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.
You can either move it inside src/, or add a symlink to it from project’s node_modules/.
Thankfully these have resolved by the Storybook team.
To try latest features, install as:
npx sb@next init
Once complete, Storybook will scaffold configuration and an example set of stories under:
.storybook/
— Configuration of Storybooksrc/stories/
— Example stories
To start Storybook, execute:
yarn storybook
Then, navigate to http://localhost:6006/ to view the interface:
Creating Storybook Docs
Storybook uses MDX for creating Storybook Docs — a great way to document your components.
Under the src/stories
folder, create any quantity of MDX documentation by creating a new file named [topic].stories.mdx
and specifying the title in the <Meta tile="section/topic]" />
meta block.
Here’s an example introduction.stories.mdx file:
Above example combines markdown with styled HTML, would would produce the following page in the Storybook UI:
Creating a Story
Storybook automatically scaffolds some example stories, in which example components are defined in the src/stories
folder. Of course, you would access your components as normal from src/
— these are only for demonstration purposes. In fact, you can delete everything in that stories folder to start fresh.
Under the src/stories
folder, create any quantity of stories by adding new files named [topic].stories.js
to group a collection of components.
In each story, load React and components for the story, exporting a title, argument types, and components to load in Storybook:
Above examples would show a Button
component that has the following argument types:
- Background Color, using the a color control
- Primary, using a boolean toggle switch
- Label, using a string text input
- Size, using a radio control to display an enumeration of possible options
By default, the component will default to primary enabled with label “Primary Button” by passing args to the component.
Storybook will load this story as follows:
There’s a wide range of controls builtin, defined in Storybook’s Essential Controls documentation. These include array, boolean, number, range, text, color, date, radio, check, and select.
Proxying Endpoints and Web Sockets
If your development environment incorporates multiple servers providing streaming data, static assets, and APIs through other backend servers, you may need to implement middleware to proxy the requests.
For example, if your React app implements proxies leveraging http-proxy-middleware
, you can incorporate the same functionality with Storybook by creating a file under the .storybook/
folder named: middleware.js
that includes:
Above, web socket requests are proxied to localhost port 4002, and two endpoints of /photos
and /api
are proxied to localhost port 3001.
Redux, Theming, and Routing
Three additional topics are grouped here, as they all relate the to the preview decorator of Storybook.
- Incorporating a Redux store
- Integrating with Material UI theme provider
- Handling routing issues with React Router
All stories can implement a global decorator to provide this functionality by creating a file under the .storybook/
folder named: preview.js
that includes the following:
This will wrap functionality around stories rendered by Storybook.
Redux
Storybook is more intended for components and properties opposed to containers that manage state in a store.
However, it may be necessary to incorporate a provider in your stories, especially for larger projects with significant lifespan.
In doing so, this might help expose and encourage decoupling logic and presentation; or, just prevent errors if your components tightly integrate with Redux stores.
In the preview decorator, add your Redux provider and store.
Material UI Theming
If your solution incorporates theming, such as Material UI’s theming system, it is ideal to view your components with your theme provider.
In the preview decorator, add your theme provider and theme definition.
React Router
Routing will generally have little meaning in Storybook; however, if your components include functionality such as useLocation
hook from React Router DOM, they will throw an error unless some kind of router is implemented.
import { useLocation } from "react-router-dom";const MyComponent = () => {
const location = useLocation();
useEffect(() => {
// something happens...
}, [location]);
To compensate for this, include a router such as MemoryRouter
from React Router in the preview decorator.