A Dive into React Storybook
Tags: javascript, react, storybook, webdev
Published: 2022-04-23 11:36:26

by [Emmanuel Odioko](https://blog.openreplay.com/authors/emmanuel-odioko)

When it comes to development testing and documenting components, Storybook is the best tool, in my opinion. Storybook is an awesome tool to help you build, demo, and document component libraries.

Components are files that make up the application. Though they make up the main application(`App.js`), they need to be in the application for it to be rendered in the browser because they don't have `Index.js` files attached to them. Unlike the main application, this would be a problem if the project is massively built with numerous functionalities.

This is where Storybook comes in handy. It helps highlight components with various tools available for your use and makes our life much easier. Storybook provides you with the runtime environment to bring components to life with change detection, providing a nice-looking user interface for your components.

In this article, I will elaborate on how we can use Storybook with React and how to best integrate Storybook into any React project. For this tutorial to make sense, you need to understand that Storybook can be used with many frameworks like Vue, Angular, and even plain vanilla Javascript. However, within the scope of this tutorial, we will be using React only. You need prior knowledge of React and [how to use prop types](https://www.freecodecamp.org/news/how-to-use-proptypes-in-react/). These are the tools to be installed ;

- Node.js and npm `Node ≥v14.0.0 and npm ≥v5.6`
- React version 18.0
- StoryBook
- Proptype

## Setting up the Development Environment 

Open up your command line, and create a folder with a name of your choice; we'll use `stories-article`. Then, move into the folder and follow these steps to start up your project quickly:

```
npx create-react-app stories-article
```
    
We do not need all the dependencies that come with React application, but we need the components. After the React application is installed, we have to remove some scripts. To take off the nugatory scripts, do this in the folder:

```   
npm uninstall - -save react-scripts
```
        
Clear up the `App.js` file and return anything. Yes, this must have left you thinking because there is no place to render our code in the browser. This is because we do not have a main application but a component, and we haven't installed Storybook yet.

The next thing to install is Proptype.

```        
npm install - -save prop-types 
```

Then, install Storybook.

```
npx sb init
```

If you run into warning errors, please install these plugins.

```
npm install --save-dev webpack webpack-cli html-webpack-plugin webpack-dev-server webpack-dev-middleware 
```

Inside `package.json`, replace the script we deleted with Storybook just like this;

```
    "scripts": {
      "start": "start-storybook -p 6006",
      "build": "build-storybook"
```      

To start up Storybook, run:

```
npm start
```    

Now Storybook is up and running.


![We should  get this after properly installing Storybook](https://blog.openreplay.com/static/d1406df7f9ce817ae0e5b3eb5f1bf1f3/e8a69/image01.png)


You can always refer [here](https://storybook.js.org/docs/react/get-started/install) for more instructions.

## Button Component

Let's create a basic Story. For instance, we have a full-stack application, and one of the activities of the components is to call a function that increments whenever it is clicked. We want to see this working before importing the function to our main `App.js` file. Let's create the button and add functionalities on React. First, create a component, and name it `Button.js`.

```javascript
import React, { useState } from "react";

function Button() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount((prev) => prev + 1);
  };

  return (
    <div>
      <h2>counter:{count}</h2>
      <input
        type="button"
        value="increment"
        onClick={increment}
      />
    </div>
  );
}

export default Button;
```

 
We could picture this component as an actor performing on a stage without a spotlight. You would think variably if the performer is backstage or on stage, but you are sure he is performing.

Just like the components, the increment function could be working fine if you console.log it. Still, there is no place to see it as a user to help the user-interface experience unless we do something: either we import it in our `App.js` file, or we deploy the use of Storybook. The latter is why this article was written. We may create a basic Story right now.

First, we need to create our own story, and we will do that by going to the Stories folder and creating one. I will name mine `Button.stories.js`. Adding `stories" before the `.js` tells Storybook what this file is.

Secondly, we need to import the Button component and export our stories. We will also need to export a default object that carries the actual Story, and carries a title, and the component to be rendered.

```javascript
import Button from "../component/Button";

export default {
  title: "Button",
  component: Button,
};
```  

Finally, we need to tell Storybook what our stories are, as we had primary and secondary stories in our button category. To implement a clear-cut named story, we have to export a function that will return our component, and whatever name we give this function, that's the name of our story in our button component.

```javascript
export const increment = () => <Button/>;
```
  
![Storybook up and running](https://blog.openreplay.com/static/b94dcf1ce1e042cef2afc6ab5313815d/a2619/image02.png)


As we can see, this works just fine. That's how you can create a basic story.




## Stack component 

For the advanced story, we will create a brand new folder named `Stack.js`. Our `Stack.js` component takes in children, direction, and a wrap variable with a bit of CSS styling.

```javascript
function Stack({
  children,
  spacing = 2,
  direction = "row",
  wrap = false,
}) {
  const style = {
    display: "flex",
    gap: `${spacing * 0.3}px`,
    flexWrap: wrap ? "wrap" : "nowrap",
    flexDirection: direction,
  };
  return <div style={style}>{children}</div>;
}

export default Stack;
```

We also need a `stack.stories.js` folder, which we should create right away. In the stack Story, we need to add children to it. We should be able to change the number of children being passed into our stack by adding an argument that we could pass into the Storybook to control how many children elements we see in a storybook. This is where argTypes comes into place. First, we need to export the default title and components we will see.

```javascript
import Stack from "../component/Stack";

export default {
  title: "Component/stack",
  component: Stack,
  argTypes: {
    childrenNumber: { type: "number", defaultValue: 5 },
  },
};
```     

Component/stack makes Stack a child that pops up when clicking the component. We can name our argument whatever we want. In my case, I called it `childrenNumber`,  and I gave it a type of `number`, so we can choose and control how many children we desire. I gave it a default value of 5.



## Open Source Session Replay

_[OpenReplay](https://github.com/openreplay/openreplay) is an open-source alternative to FullStory and LogRocket. It gives you full observability by replaying everything your users do on your app and showing how your stack behaves for every issue. OpenReplay is self-hosted for full control over your data._

![replayer.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1647097041609/Qi6sMOaaB.png)

_Happy debugging for modern frontend teams - [start monitoring your web app for free](https://github.com/openreplay/openreplay)._





## Interactivity

We need to configure our story so that controls quit displaying "this story is not configured to handle controls". To fix this, we need to add some code. This may not be very clear, but hang on.

![A problem: the story is not configured to handle controls](https://blog.openreplay.com/static/93fc29e1664b699e3b4480842bbcd255/51cd9/image03.png)

We need to set up a plinth function which we will call a paradigm (because it serves as a model for what our various stories shall follow). The paradigm function will return our Stack and pass our argument `childrenNumber` into it. Here we need an array with the value of `childrenNumber`. We need to map it, so we get a number(any number), and inside the number, we want to return a string with the value `love` in a `div`. 
 
```javascript
const paradigm = ({ ChildrenNumber, ...args }) => (
  <Stack {...args}>
    {[...Array(ChildrenNumber).keys()].map((n) => (
      <div>{"love"}</div>
    ))}
  </Stack>
);
```
     
Now we can export our Story as a horizontal component baring our control arguments. 

```javascript
export const Horizontal = paradigm.bind({});

Horizontal.args = {
  direction: "",
  spacing: 2,
  wrap: false,
};
```

We get this displayed on our screen.

![this is what is rendered on our Storybook](https://blog.openreplay.com/static/de6bce408ea0437e5bda7c6995c9d9c1/2b2a8/image04.png)


Let's style the div.

```
style = {{
  width: "70px",
  height: "70px",
  backgroundColor: "blue",
  display: "flex",
  justifyContent: "center",
  alignItems: "center",
}}
```
      
![after styling the div](https://blog.openreplay.com/static/d55999dd8007fab409a0665a8c0dc816/e9cd7/image05.png)

The important thing to note about all of this, as you could see here,

```javascript
export default {
  title: "Component/stack",
  component: Stack,
  argTypes: {
    childrenNumber: { type: "number", defaultValue: 5 },
  },
};
```

We needed to pass an additional argument that is not needed anywhere in our component, but only needed for Storybook. We defined that inside our argtypes and then applied it in our `paradigm`, using that argument to pass all the additional arguments that the Stack needs.

## proptypes

Proptypes help ensure the passed value is of a correct data type. Proptypes used to be included in React, but now it is separate. That's why it was individually installed. What's the benefit of Proptype in Storybook? Proptypes inform Storybook on descriptions and tell Storybook what values are being passed. Automatically, Storybook is built to integrate and display these functionalities.

This is a little outside the scope of our tutorial, but it's needed, and here is why. Even after configuring our controls, we got a few errors (our controls are not all functional). That's probably because our values passed in the `stack.js` component have not been described to Storybook, and Storybook doesn't know what they are. That's why using Proptypes is essential. If this is confusing to you, you could read [this article](https://www.freecodecamp.org/news/how-to-use-proptypes-in-react/) on Proptype.

To describe our values, so we can manipulate our controls and Storybook knows what is renderable, we need to add this in our `stack.Js` component right above the export default.

```javascript
Stack.propTypes = {
  spacing: PropTypes.number,
  wrap: PropTypes.bool,
  direction: PropTypes.oneOf(["row"]),
};
```

![before the proptype was added](https://blog.openreplay.com/static/65f08698e5a98dbebed485386951f2d6/e6cfb/image06.png)

Now we can return to Storybook and see that everything is interactive. We can wrap our div and increase or decrease spacing.

![after the proptype was added](https://blog.openreplay.com/static/e1f66434c0ca510e6d06624358f2a678/4643d/image07.png)

## Conclusion

One of the peculiarities of being a developer is keeping up to date on new technologies in the development space because they help immensely, just like Storybook. Knowing how to use them could ease stress, and one of the keys to being at the pick of your development career is finding tools for fast and efficient delivery.


## Further Reading
1. Ateev Duggal. [How to use proptypes in React](https://www.freecodecamp.org/news/how-to-use-proptypes-in-react/), 2022.
2. Storybook docs. [How to write stories](https://storybook.js.org/docs/react/writing-stories/introduction).