How to Use React Storybook to Create Reusable Components

Nowadays, user interface design is a costly process that requires effort from a lot of people, including developers, designers, testers, product managers and so on.

Companies usually create interfaces consisting of many independent components that can be reused. At the same time, designers create a design project that describes separately every detail of the design. They use a number of tools for documenting interfaces; some that come to mind are axshare.com, zeplin.com, and Photoshop, in which designers keep their work compartmentalized. This allows them to easily work on and revise the design of the project. They can update and add new pages by simply copying the elements they’ve already designed.

And what about developers? We have Angular, React, Vue, Ember, and Polymer. All these tools allow us to create reusable components. But how can we look at projects the same way that a designer does? Where can we see all components that are used in the project, learn their properties or just try them? How do we know if the component we need is already implemented? Such questions begin to emerge in medium-sized projects. Of course, you can go and ask your colleague, but a colleague can’t always get to the essence of the problem and point out a component that you can use or extend.

Here’s a typical situation: you’re going through the specs of a new page that you have to develop. All the components look familiar and you’ve seen them used elsewhere. You plan your tasks based on an understanding that some components have already been implemented. After agreeing on the timing and starting a new sprint, you dig around in the code a bit and are horrified to realize that the existing components are not appropriate for reuse. Now you have three options, none of which are great:

  • Copy and paste the existing component, and tweak the copy until it suits your needs. But that creates tech debt and a nasty “code smell”. In fact, Kent Beck and Martin Fowler call it their number one code smell in Refactoring: Improving the Design of Existing Code
  • Modify/improve/extend the existing component. But experience suggests that this can be expensive, and can become more expensive with each modification/improvement/extension.
  • Develop a new, multifunctional component. This is an ok option but it can take a lot of time.

Introducing React Storybook

With the growing trend towards distributed development and components that can be reused, there is a need for additional tools. Let’s take a look at React Storybook. Using React Storybook in your project means you can easily avoid the situation described above.

From the project README:

Storybook is a development environment for UI components. It allows you to browse a component library, view the different states of each component, and interactively develop and test components.

Storybook runs outside of your app. This allows you to develop UI components in isolation, which can improve component reuse, testability, and development speed. You can build quickly without having to worry about application-specific dependencies.

Here are some featured examples that you can reference to see how Storybook works: https://storybook.js.org/examples/

Storybook comes with a lot of addons for component design, documentation, testing, interactivity, and so on. Storybook’s easy-to-use API makes it easy to configure and extend in various ways. It has even been extended to support React Native development for mobile

Let’s look at how to use Storybook from the perspective of various participants in the creation process and the secondary processes supporting the application interface.

How to Use Storybook If You Are A…

UI \ UX designer

You will have the opportunity to try components implemented by the developer, see all the possible states of the component, and provide feedback.

Developer

You will have a library of components in React Storybook.  You will no longer have to guess whether you have a component or not. You can play around with any component and find out the possibilities of using it in the context of your current task. It is very important for the developer to be able to see all the components that are used in a project and know all their features. Of course you can spend a lot of time reading the source code, but it will be much easier to find the right component with the desired properties visually, and then go into details.

You can also develop components in an isolated environment, which does not require raising the entire project locally. An isolated environment allows you to develop components with a more robust API allowing reuse in any part of your project. You can think about the incoming parameters from the consumer’s point of view and understand what parameters would be convenient for the potential consumer. Also you are thinking about isolating styles. Among other things, you get a real workbench for component development. You can customize the Storybook environment as you like, and take advantage of features like HMR out of the box.

QA

You will have the opportunity to test each component separately and independently of the others. There is no need to launch the whole project. You can simply open React Storybook with the components you are interested in and carry out absolutely any E2E tests.

Product Manager

As a Product Manager planning a new feature, it’s useful to know about existing elements and try them interactively.

Installing React Storybook

Since Storybook is part of the node / npm ecosystem, this is done very simply. You can install the basic cli tool using one of your favorite Yarn package managers or NPM.

$ yarn global add @storybook/cli

For experiments, you will need a project. As an example, take a workpiece from the create-react-app. I’ll omit the description and special features of create-react-app, which is a very useful and easy-to-understand tool that you can read more about here.

$ yarn global add create-react-app # Install and create a new project using create-react-app
$ create-react-app my-app # create a project
$ cd my-app; yarn start; # go to the project directory and run it

The browser will open a fresh project created using the create-react-app. Now we have an application for experiments with React Storybook, so let’s get started. In order to initialize Storybook, run the following command while at the root of the project:

$ getstorybook

This command determines the type of the project, makes the necessary checks and establishes dependencies

image

Then, in the project, there will be newly created folders .storybook and stories

image
The .storybook folder contains various configuration files. We will deal with them later. At the moment we are interested in the stories folder.

It contains a library of components. After initializing Storybook in the project, by default, a file with one example is created. Let’s run Storybook and look at it.

$ yarn storybook

Storybook will be available at http://localhost: 6006/

imageThe page has a simple interface. On the left, we see a panel with hierarchical folders of searchable components. On the right is a fairly large work area in which your components and other information will be displayed. The bottom panel is used as an interactive tool, to which we can write information and component controls. The layout of these panels is configurable.

For the sake of this example, let’s use react-select rather than create our own component.

$ yarn add react-select

Create a Select folder with the index.js file in the src next

import React, { Component } from 'react';
import Select from 'react-select'; 
import 'react-select/dist/react-select.css';

class SelectWrapper extends Component {
  state = {
    value: null
  }
  
  onChange = (value) => {
    this.setState({
      value,
    })
    this.props.onChange(value)
  }

  render() {
    return (
      <Select { ...this.props } value={this.state.value} onChange={this.onChange} />
    )
  }
}

SelectWrapper.defaultProps = {
  onChange: () => {}
}

export default SelectWrapper;

This is just a small wrapper for storing the state of the component.
Now let’s add our component to the Storybook. This is done very simply:

import Select from '../Select'
storiesOf("React select", module) 
    .add('General', () => <Select options={options} />)

The code is intuitive. storiesOf creates a category in which you can add different components.

Let’s add react-select to our Storybook with the option of multi-select:

storiesOf("React select", module) .add('General', () => <Select options={options} />) .add('With multi prop', () => <Select options={options} multi />)

image

Building React Storybook

An important feature is the ability to compile Storybook into static files, which can be published for example on some site or used internally as documentation.  Just run

$ yarn build-storybook

By default, the files are added to storybook-static. You can open them in any browser.

Webpack and Other Configurations

By default, Storybook tries to understand your environment and use a number of settings that allow you to compile and display Storybook. But there are times when you can not do without additional configuration.  You can add webpack.config.js to the .storybook directory.  Often such a configuration will be very simple

// you can use this file to add your custom webpack plugins, loaders and anything you like.
// This is just the basic way to add additional webpack configurations.
// For more information refer the docs: https://storybook.js.org/configurations/custom-webpack-config

// IMPORTANT
// When you add this file, we won't add the default configurations which is similar
// to "React Create App". This only has babel loader to load JavaScript.

const mainConfig = require('../webpack.config')

module.exports = {
  plugins: [
    // your custom plugins
  ],
  module: mainConfig.module
};

As you can see, it’s just importing the config from the main project. In our experiments, you will not need this config.

Using Add-ons

Storybook has a number of recommended add-ons

  • a11y – Test components for user accessibility in Storybook
  • actions – Log actions as users interact with components in the Storybook UI
  • background – Let users choose backgrounds in the Storybook UI
  • centered – Center the alignment of your components within the Storybook UI
  • events – Interactively fire events to components that respond to EventEmitter
  • graphql – Query a GraphQL server within Storybook stories
  • info – Annotate stories with extra component usage information
  • jest – View the results of components’ unit tests in Storybook
  • knobs – Interactively edit component prop data in the Storybook UI
  • links – Create links between stories
  • notes – Annotate Storybook stories with notes
  • options – Customize the Storybook UI in code
  • storyshots – Easy snapshot testing for components in Storybook
  • storysource – View the code of your stories within the Storybook UI
  • viewport – Change display sizes and layouts for responsive components using Storybook

Let’s go back and look at the default examples.

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 plugin “action” creates a kind of function, the result of which you will see in Action Logger. This can be useful for logging parameters by type onApply or onClick.

image

Also useful are the so-called “knobs”. They allow you to edit the transmitted parameters to a component.

yarn add @ storybook/addon-knobs

You must import the installed module into addons.js in the .storybook directory.

import '@storybook/addon-knobs/register'

And in stories / index.js, import the knobs we need

import {withKnobs, text, boolean, number} from '@ storybook/addon-knobs'

Let’s add the ability to interactively manipulate the button

storiesOf('Button', module)
  .addDecorator(withKnobs)
  .add('with text', () => <Button onClick={action('clicked')}>Hello Button</Button>)
  .add('with some emoji', () => <Button onClick={action('clicked')}>   </Button>)
  .add('Interactive demo', () => <Button disabled={boolean('Disabled', false)}>{text('Button text', 'Default')}</Button>)

image
Now we can change the text of the button and use boolean to set the state of the button.

Another very useful addition is Info, this add-on automatically documents the external component API.

yarn add @ storybook/addon-info

Import the module:

import { withInfo } from '@storybook/addon-info'

And let’s change the code of our button a little:

.add('Interactive demo 2', withInfo('doc string about my button component')(() =>
    <Button disabled={boolean('Disabled', false)}>{text('Button text', 'Default')}</Button>
  )

On the right, there is a button with which you can open detailed information about the component

image
You can also display this information without having to open it, directly on the work area together with the component.

.add('Interactive demo 3', withInfo({
    text: 'doc string about my button component',
    inline: true,
  })(() =>
      <Button disabled={boolean('Disabled', false)}>{text('Button text', 'Default')}</Button>
    ))

React Storybook: Creating Reusable Components

As you can see, React Storybook is very easy to use, has a lot of options and add-ons, and gives you visibility into your library of components. The rest of the team can see and try a component even before it is used on a page, which allows you to get feedback from designers much earlier. Beginners on the team will no longer be lost wondering if components already exist or if they can be used for the current task. Also Storybook allows you to develop components in an isolated environment, which helps strengthen your interfaces.

Illustrations: https://www.behance.net/furkansoyler

About Dmitry Olkhovoi

Dmitry Olkhovoi is a JavaScript engineer at Conductor

Related Posts