Passar a escrever os seus componentes no padrão "compound components" pode te salvar muitas horas de refactor.
Tags: react, javascript
Published: 2021-06-19 16:27:03

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sp3bh3rwg4riyctm1o1m.png)

 
> Como eu quero que esse texto seja uma leitura rápida não vou colocar nenhuma implementação do código

Vamos começar imaginando que o time de design lhe entregou o Menu abaixo no figma e agora chegou a sua hora de implementa-lo

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yzwsvxpycgzfpxrp6vfu.png)

Uma implementação válida poderia ser:

```jsx
<Menu
  trigger={<MoreIcon />}
  config={{
    onClick: someFunction,
    label: "Delete"
  }}
/>
```

Parabéns! Você conseguiu entregar o menu e já pode pegar outras tarefas.

---

Passou algum tempo e agora aquele menu que você fez precisa ser mais flexível e capaz de receber mais features, como por exemplo, mais um botão para poder editar algo.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ta7uwekf1f4rqkjjda3z.png)

Vendo o novo design, você decide atualizar o objeto de configuração, para algo semelhante com o código abaixo:

```jsx
<Menu
  trigger={<MoreIcon />}
  config={[
    {
      label: 'Edit',
      onClick: someFunction1,
    },
    {
      label: 'Delete',
      onClick: someFunction2,
    }
  ]}
/>
```

uhuuuul! Esse menu não é mais probl… POW, surge do nada, sem nenhum aviso um novo menu…

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zn2f9tpuajo10isk6vnq.png)
 
Agora você começa a ficar chateado por estar preso nesse menu durante um bom tempo e, mais uma vez, você precisa voltar nele e alterá-lo.

```jsx
<Menu trigger={<MoreIcon />} config={[
  {
    title: "safe actions",
    items: [
      {
        label: 'Edit',
        onClick: someFunction1,
        align: 'left',
      }
    ],
    hasDividerBellow: true,
  },
  {
    title: "unsafe actions",
    items: [
      {
        label: 'Edit',
        onClick: someFunction2,
        align: 'left',
        color: 'red',
      }
    ],
    hasDividerBellow: false,
  },
]} />
```

Você decide seguir a implementação com o objeto de configuração a cima e pronto! Acabamos com a nossa historinha e já podemos analisar alguns fatores sobre ela.

---

Se em algum momento você chegou nesse ponto, provavelmente pensou algumas coisas, como:
* <i>Esse código tá uma bagunça!!!</i>
* <i>Se eu soubesse que o componente final seria, teria feito um código muito melhor!</i>
* <i>Esse código tá muito complexo, acho que vou fazer um refactor depois</i> (SPOILER: O depois nunca chegou)

<b>ISSO É NORMAL</b>, principalmente se você for iniciante. Então, vamos seguir adiante e analisar quais os maiores problemas da abordagem a cima:

* Toda feature nova vai precisar de um novo refactor
* Conforme a quantidade de features do seu objeto aumentar, mais difícil vai ser manter o componente devido ao aumento da complexidade, ou seja não é muito escalável
* A legibilidade do seu código vai diminuindo cada vez mais.

OK, o que podemos fazer para evitar isso? existe uma solução? SIM!

---

## Compound Components no lugar de objetos de configuração

A ideia por trás dos <i>compound components</i> baseia-se na mudança da quantidade de componentes: anteriormente, você possuía apenas um componente com um objeto de configuração; e agora, você tem dois ou mais componentes que trabalham juntos para realizar algo. Ou seja, você vai separar a sua solução única em mais de um componente para que depois eles possam compor a solução final. (daí o nome 🤯)

Vamos ver então como ficaria as implementações acima utilizando o padrão do <i>compound components</i>.

Para o primeiro caso:

```jsx
<Menu trigger={<MoreIcon />}>
  <Menu.Container>
    <Menu.Button label="Delete" onClick={someFunction1} />
  </Menu.Container>
</Menu>
```

Enquanto o segundo ficaria parecido com:

```jsx
<Menu trigger={<MoreIcon />}>
  <Menu.Container>
    <Menu.Button label="Edit" onClick={someFunction1} />
    <Menu.Button label="Delete" onClick={someFunction1} 
  </Menu.Container>
</Menu>
```

E o último ficaria:

```
<Menu trigger={<MoreIcon />}>
  <Menu.Container>
    <Menu.Section title="safe actions">
      <Menu.Button label="Edit" onClick={someFunction1} />
    </Menu.Section>
    <Menu.Divider />
    <Menu.Section title="unsafe actions">
      <Menu.Button label="Delete" onClick={someFunction1} 
    </Menu.Section>
  </Menu.Container>
</Menu>
```

---

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/myfdxqfv78924duwc9ao.png)

## Concluindo

A grande vantagem de seguir esse padrão esta na sua flexibilidade. No caso acima, por exemplo, você não precisaria ficar voltando no componente e refatorando o código toda vez que o menu precisasse de uma feature nova, você iria apenas criar novos componentes.

Outra vantagem está na legibilidade, já que cada componente tende a ser pequeno e/ou ter uma responsabilidade bem específica, facilitando a manutenção dos mesmos.