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.