StoryBook meets redux
Develop and test components in isolation is great, I wrote about that in a previous post, but sometimes we rely on other software to develop our own.
That’s the case with most of the redux ecosystem; Redux gave us an excellent model to build our apps then people started to build abstractions on top of it. One of the abstractions I like the most is redux-form.
Redux form enables consistent form handling for all the projects we do here at ingenious; it’s not just a handy tool, it’s a significant normalization layer, a greater abstraction everybody can use and rely on.
During our dev process, we use StoryBook for almost all the components we create but as you might expect if you try to use connected components like the ones enhanced by the reduxForm
HOC it will fail.
The issue here is that StoryBook knows nothing about the store (that’s the beauty of it, right?), while that’s an advantage most of the time, we also want to preview/test form components.
Introducing the Provider
What gives the ability to our components to use the redux store is the Provider
, a component that's in charge of making everything else connectable.
Usually most react redux apps have something similar to this:
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { Router, browserHistory } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import routes from './config/routes';
import configureStore from './store/configureStore';
const store = configureStore();
const history = syncHistoryWithStore(browserHistory, store)
render(
<Provider store={store}>
<Router history={history} routes={routes} />
</Provider>,
document.getElementById('root')
);
Wrapping everything with Provider
is what gives us the ability to query and subscribe to the store.
.addDecorator
Luckily for us, we can tell storybook to decorate components with anything we want.
The addDecorator
method accepts a function that returns a component. This API is super useful when we need some wrapping styles or like in our case to make our components redux aware.
import React from 'react';
import { storiesOf } from '@kadira/storybook';
storiesOf('Signup form', module)
.addDecorator(story => /*Do whatever you want with story*/)
.add('empty form', () => <SignupForm />);
The story
param is also a function that returns the component we want to decorate; now we can make something useful with it.
import React from 'react';
import { storiesOf } from '@kadira/storybook';
import { Provider } from 'react-redux';
import { browserHistory } from 'react-router';
import configureStore from '../store/configureStore';
const store = configureStore(browserHistory);
storiesOf('Signup form', module)
.addDecorator(story => <Provider store={store}>{story()}</Provider>)
.add('empty form', () => <SignupForm />);
And 💥 redux aware components inside storybook.
Hiding the complexity
So far we were able to wrap everything with Provider
, but we still need to create a store
every time we want to use it. We can reduce boilerplate by creating our own Provider
in charge of setting up the store
and configuring the react-redux provider.
// stories/Provider.js
import React from 'react';
import { Provider as ReduxProvider } from 'react-redux';
import { browserHistory } from 'react-router';
import configureStore from '../store/configureStore';
const store = configureStore(browserHistory, {});
export default function Provider({ story }) {
return (
<ReduxProvider store={store}>
{story}
</ReduxProvider>
);
};// stories/SignupForm.js
import React from 'react';
import { storiesOf } from '@kadira/storybook';
import { Provider } from './Provder';
storiesOf('Signup form', module)
.addDecorator(story => <Provider story={story()} />)
.add('empty form', () => <SignupForm />);
This is a bit easier to read and helps with code reuse.
Disclaimer
I didn’t invent any of this, the addDecorator
method is well documented on the storybook website, and some of the techniques are answers to questions people have had on the react-storybook repo.
Do you like React and want to help us building amazing products? Drop us a line.
About ingenious
Ingenious is a distributed company with offices in Montevideo, Uruguay, and Denver, Colorado, and people in more than five countries. We build software for challenging industry segments like healthcare and government where most of the software sucks.