When you start a new front-end project, the first thing you usually do is create a beautiful design. You carefully plan and draw all of your UI components, as well as each state or effect they may have. However, during development, things usually start to change. New requirements, as well as unforeseen use cases pop up here and there. The initial beautiful component library cannot cover all of these requirements and you start to expand it with new designs.
It's good if at this point you still have a design expert around, but all too often they have already switched to a different project and left the developers to cope with these changes. As a result, the consistency of the design begins to slip. It becomes difficult to track what components you already have in your library and what states and appearances they may have.
To avoid this artistic mess it's usually a good idea to create separate documentation for all of your components. There are various tools for such purposes, but in this article, we'll focus on a tool designed particularly for React applications — React Storybook. It allows you to easily browse your collection of components and their functionality. A living example of such an app is the gallery of React Native components.
Why Do You Need React Storybook?
So how does this showcase help? To answer this question, let's try to put together a list of people who take part in the development of UI components and assess their needs. Depending on your workflow this list might differ, but the usual suspects are the following:
Designer or UX expert
This is the person responsible for the look and feel of the user interface. After the mockup phase of the project is finished, often the designer leaves the team. When new requirements arise, they need to quickly catch up on the current state of the UI.
Developer
The developer is the one who creates these components and probably the main beneficiary of a style guide. The two major use cases for the developer are being able to find a suitable component from the library and be able to test them during development.
Tester
This is the meticulous person who makes sure the components are implemented as expected. A major part of a tester's work is making sure that a component behaves correctly in every way. And although this does not eliminate the need for integration testing, this is often more convenient to do separately from the project itself.
Product owner
The person who accepts the designs and the implementation. The product owner needs to make sure each part of the project looks as expected and that the brand style is represented in a consistent manner.
You've probably noticed that a common denominator for everybody involved, is having a single place containing all of the components at once. Finding all of them in the project itself can be quite tedious. Think about it, how long will it take you to find all possible variations of buttons in your project, including their states (disabled, primary, secondary etc)? That's why having a separate gallery is much more convenient.
If I've managed to convince you, let's see how we can set up Storybook in a project.
Setting up React Storybook
To set up React Storybook the first thing you'll need is a React project. If you don't have a suitable one at the moment, you can easily create one using create-react-app.
To generate a Storybook, install getstorybook
globally
npm i -g getstorybook
Then navigate to your project and run
getstorybook
This command will do three things:
- Install @kadira/storybook into your project.
- Add the
storybook
andbuild-storybook
scripts to yourpackage.json
file. - Create a
.storybook
folder which contains the basic configuration and astories
folder with a sample component and story.
To run Storybook, execute npm run storybook
and open the address displayed (http://localhost:9009/). The app should look like this:
Adding New Content
Now that we have React Storybook running, let's see how we can add new content. Each new page is added by creating stories. These are snippets of code that render your component. An example story generated by getstorybook
looks like this
//src/stories/index.js
import React from 'react';
import { storiesOf, action, linkTo } from '@kadira/storybook';
import Button from './Button';
import Welcome from './Welcome';
storiesOf('Welcome', module)
.add('to Storybook', () => (
<Welcome showApp={linkTo('Button')}/>
));
storiesOf('Button', module)
.add('with text', () => (
<Button onClick={action('clicked')}>Hello Button</Button>
))
.add('with some emoji', () => (
<Button onClick={action('clicked')}> </Button>
));
The storiesOf
function creates a new section in the navigation menu, and the add
method creates a new subsection. You are free to structure the storybook however you see fit, but you cannot create hierarchies deeper then two levels. A straightforward approach to structuring your Storybook is creating common top-level sections such as "Form inputs", "Navigation" or "Widgets" for groups of related elements, and sub-sections for individual components.
You are free to choose where to place your story files: in a separate stories folder or next to the components. I, personally, prefer the latter since keeping the stories close to the components helps to keep them accessible and up to date.
Stories are loaded in the .storybook/config.js
file which contains the following code:
import { configure } from '@kadira/storybook';
function loadStories() {
require('../src/stories');
}
configure(loadStories, module);
By default, it loads the src/stories/index.js
file and expects you to import your stories there. This is slightly inconvenient since it would require us to import each new story we create. We can modify this script to automatically load all of the stories using Webpack's require.context method. To distinguish story files from the rest of the code, we can agree to add a .stories.js
extension to them. The modified script should look like this:
import { configure, addDecorator } from '@kadira/storybook';
import React from 'react';
configure(
() => {
const req = require.context('../src', true, /.stories.js$/);
req.keys().forEach((filename) => req(filename));
},
module
);
configure(loadStories, module);
If you're using a different folder for your source code, make sure you point it to the correct location. Re-run Storybook for the changes to take effect. The Storybook will be empty since it no longer imports the index.js
file, but we'll soon fix that.
Writing a New Story
Now that we've slightly tailored Storybook to our needs, let's write our first story. But first of all we need to create a component to showcase. Let's create a simple Name
component to display a name in a colored block. The component will have the following JavaScript and CSS.
import React from 'react';
import './Name.css';
const Name = (props) => (
<div className={'name ' + (props.type ? props.type : '')}>{props.name}</div>
)
Name.propTypes = {
type: React.PropTypes.oneOf(['highlight', 'disabled']),
}
export default Name;
.name {
display: inline-block;
font-size: 1.4em;
background: #4169e1;
color: #fff;
border-radius: 4px;
padding: 4px 10px;
}
.highlight {
background: #dc143c;
}
.disabled {
background: #999;
}
As you've probably noticed, this simple component can have three states: default, highlighted and disabled. Wouldn't it be nice to visualize all of them? Let's write a story for that. Create a new Name.stories.js
file alongside your component and add the following contents:
import React from 'react';
import { storiesOf, action, linkTo } from '@kadira/storybook';
import Name from './Name';
storiesOf('Components', module)
.add('Name', () => (
<div>
<h2>Normal</h2>
<Name name="Louie Anderson" />
<h2>Highlighted</h2>
<Name name="Louie Anderson" type="highlight" />
<h2>Disabled</h2>
<Name name="Louie Anderson" type="disabled" />
</div>
))
Open Storybook and have a look at your new component. The result should look like this:
Feel free to play around with how the component is displayed as well as with its source. Note that thanks to React's hot reloading functionality, whenever you edit the story or the component, the changes will instantly appear in your Storybook without the need to manually refresh the browser. However refreshing might be required when you add or remove a file. Storybook doesn't always notice such changes.
Continue reading %React Storybook: Develop Beautiful User Interfaces with Ease%
by Pavels Jelisejevs via SitePoint
No comments:
Post a Comment