Utilizando o Storybook para componentes
Tags: react, storybook
Published: 2023-02-16 15:45:16

## Para que serve o Storybook?

O Storybook é uma ferramenta bastante útil para desenvolvedores de aplicações web baseadas em componentes. Ele permite a criação de componentes de forma isolada, tornando mais fácil testar diferentes estados, cores e propriedades.

Sabe aquele botãozinho que ao clicar, deve ter seu texto mudado, e de acordo com isso, também deve mudar sua cor? Com o Storybook, a tarefa de testar essa funcionalidade se torna muito mais fácil.

Além disso, o Storybook ajuda a criar uma documentação para os componentes, o que facilita o trabalho em equipe.

O Storybook é amplamente utilizado para desenvolvimentos baseados em Component Driven UI. Neste tipo de abordagem, os componentes são criados primeiro e depois as páginas são construídas a partir deles, seguindo uma estratégia "from the bottom-up".

## 
**Aqui vai um exemplo do Storybook em funcionamento:**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xf1kp15ye4r1yiufp19k.gif)


### Instalando o Storybook

Para instalar o Storybook na sua aplicação React, seja com CRA (Create React App) ou Vite, basta executar o seguinte comando no terminal:

```
npx sb init

```

Com isso, serão instalados alguns arquivos e pastas novas em seu projeto. A pasta `.storybook` contém as configurações padrão do Storybook, enquanto a pasta `stories` é destinada a armazenar os seus stories.

Para inicializar o Storybook após a instalação, execute o seguinte comando:


```
npm run storybook

```

Nota: É recomendável que você exclua todos os arquivos na pasta `/stories/`, pois eles não serão utilizados e podem causar confusão para alguém novo no Storybook.

### **Criando um Story**

Para adicionar um story para um componente em React, crie um arquivo com o nome `[nome_do_componente].stories.jsx`, por exemplo, `Button.stories.jsx` para um componente chamado `Button`.

Exemplo de um componente `Button`:

```
import PropTypes from 'prop-types';

function Button({ label, backgroundColor = 'red', size = 'md', handleClick }) {
  let scale = 1;
  if (size === 'sm') scale = 0.75;
  if (size === 'lg') scale = 1.5;

  const style = {
    backgroundColor,
    padding: `${scale * 0.5}rem ${scale * 1}rem`,
    border: 'none',
  };

  return (
    <button onClick={handleClick} style={style}>
      {label}
    </button>
  );
}

Button.propTypes = {
  label: PropTypes.string,
  backgroundColor: PropTypes.string,
  size: PropTypes.oneOf(['sm', 'md', 'lg']),
  handleClick: PropTypes.func,
};

export default Button;
```

Em seguida, você deve criar um objeto em `Button.stories.jsx`:

```
// Em Button.stories.jsx:

import Button from '../components/Button';

export default {
  title: 'My New Button',
// O componente que você deseja renderizar, testar e adicionar um story sobre:
  component: Button, 
};

```

Agora, você pode criar uma função que retorne o seu componente e dar o nome "Red" ao seu story:


```
// Em Button.stories.jsx:

import Button from '../components/Button';

export default {
  title: 'My New Button',
  component: Button, 
};

export const Red = () => <Button label="Press Me" backgroundColor="red" />;

```

Se você estiver usando TypeScript ou o recurso "propTypes" para tipar as suas props, o StoryBook será capaz de ler, inferir e documentar essa tipagem, sabendo, por exemplo, que `label: string` e `backgroundColor: string`.

![Primeiro componente storybook, um quadrado vermelho com o texto "press me"](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o80t1n0d430t038z8js5.png)

Com isso, você já tem o seu primeiro story. Ele ainda não é interativo, mas já existe com documentação e já mostra como seria renderizado em uma página. Agora você pode torná-lo interativo para alternar as props, receber ações e assim por diante.

### Tornando nosso Story interativo

Primeiro, precisamos voltar ao nosso arquivo `Button.stories.jsx` e adicionar a seguinte linha:

```
//Em Button.stories.jsx:

import Button from '../components/Button';

export default {
  title: 'My new Button',
  component: Button 
}

// nova função aqui:

const Template = args => <Button {...args} />export const Red = () => <Button label="Press me" backgroundColor="red" />

```

Com isso, estamos criando na variável `Template` uma função que recebe alguns argumentos `(args)` - como as `props` do Componente - e retorna o `Button`, passando todos os `args` (props) para o `Button`.

Agora, para cada novo “estilo” que desejamos testar do nosso componente `Button`, basta utilizarmos o `Template` que criamos.

Por exemplo:

```
//Em Button.stories.jsx:

import Button from '../components/Button';

export default {
  title: 'My new Button',
  component: Button 
}
// mudando o Red para utilizar a Template:

const Template = args => <Button {...args} />
export const Red = Template.bind({}) 
Red.args = { 
  backgroundColor = "red",
  label: "Press me",
  size: "md",
}

```

Voltando para o Storybook, conseguimos manipular esse Story:


![Quadrado verde](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zufyqhk1r5bvl2fpier0.png)
---

### Mantendo track de “Actions” dos componentes

Quando criamos uma função chamada `onClick` como uma prop do nosso componente, o Storybook é capaz de reconhecer, por assinatura, que há algum tipo de evento acontecendo ali, e isso é mostrado na seção Actions da biblioteca.

Mas e quando temos uma função diferente, como `handleClick`, que utilizamos acima? Para tornar essa função uma Action dentro do Storybook, precisamos usar `argTypes` dentro do arquivo `Button.stories.jsx:`

```
import Button from '../components/Button';

export default {
  title: 'My new Button',
  component: Button,
  argTypes: {
    handleClick: {
      action: "handleClick"
    }
  }
}

```

Estamos dizendo para o Storybook que essa prop `handleClick` é uma Action, chamada handleClick. Essa string pode ser o que você quiser, é o nome utilizado dentro do Storybook para essa action.

```
const Template = args => <Button {...args} />export const Red = Template.bind({})
Red.args = {
  backgroundColor: "red",
  label: "Press me",
  size: "md",
}

```

Agora no Storybook → Actions, podemos encontrar a função que foi utilizada, com todas as informações de evento dela, como quando utilizamos `console.log` em um evento:


![Log de eventos do handleClick](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u075cgkk28leoa2opqyt.png)

### Criando múltiplos Stories para um mesmo componente

E agora, para finalizar (o básico) da magia do **Storybook**, podemos criar múltiplos stories para um mesmo componente, utilizando o mesmo `Template` de antes:

```
//Em Button.stories.jsx:

import Button from '../components/Button';

export default {
title: 'My new Button',
component: Button
argTypes: { handleClick: { action: "handleClick"} }
}

const Template = args => <Button {...args} />

export const Red = Template.bind({})
Red.args = {
backgroundColor = "red",
label: "Press me",
size: "md",
}
// criando um botão verde:
export const Green = Template.bind({})
Green.args = {
backgroundColor = "green",
label: "Press me",
size: "md",
}
// criando um botão pequeno:
export const Small = Template.bind({})
Small.args = {
backgroundColor = "red",
label: "Press me",
size: "sm",
}
// criando um botão grande:
export const Large = Template.bind({})
Large.args = {
backgroundColor = "red",
label: "Press me",
size: "lg",
}
// criando um botão com muito texto:
export const LongLabel = Template.bind({})
LongLabel.args = {
backgroundColor = "red",
label: "Press me hptrhpokophpoj gkpdofk pogdfpo kpgodfk pgdkpfo",
size: "md",
}

```

Ou seja, basta utilizarmos a mesma `Template`, mudando os argumentos conforme necessidade, baseado no que desejamos testar.

```
export const NomeDoStory = Template.bind({})
NomeDoStory.args = {
backgroundColor = "red",
label: "Press me",
size: "md",
}

```

No **Storybook:**


![Imagem com diferentes componentes para testar, criados em nosso código, como mostrado acima](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/coz7y5ewkm76bkdp9h9j.png)

---
Com isso, você agora já é capaz de criar novos componentes de maneira prática, utilizando os Templates, e testar os diferentes estados que aquele componente precisa ter.