DEV Community

Itelo Filho
Itelo Filho

Posted on

Passar a escrever os seus componentes no padrão "compound components" pode te salvar muitas horas de refactor.

image

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

Uma implementação válida poderia ser:

<Menu
  trigger={<MoreIcon />}
  config={{
    onClick: someFunction,
    label: "Delete"
  }}
/>
Enter fullscreen mode Exit fullscreen mode

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

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

<Menu
  trigger={<MoreIcon />}
  config={[
    {
      label: 'Edit',
      onClick: someFunction1,
    },
    {
      label: 'Delete',
      onClick: someFunction2,
    }
  ]}
/>
Enter fullscreen mode Exit fullscreen mode

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

image

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.

<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,
  },
]} />
Enter fullscreen mode Exit fullscreen mode

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:

  • Esse código tá uma bagunça!!!
  • Se eu soubesse que o componente final seria, teria feito um código muito melhor!
  • Esse código tá muito complexo, acho que vou fazer um refactor depois (SPOILER: O depois nunca chegou)

ISSO É NORMAL, 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 compound components 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 compound components.

Para o primeiro caso:

<Menu trigger={<MoreIcon />}>
  <Menu.Container>
    <Menu.Button label="Delete" onClick={someFunction1} />
  </Menu.Container>
</Menu>
Enter fullscreen mode Exit fullscreen mode

Enquanto o segundo ficaria parecido com:

<Menu trigger={<MoreIcon />}>
  <Menu.Container>
    <Menu.Button label="Edit" onClick={someFunction1} />
    <Menu.Button label="Delete" onClick={someFunction1} 
  </Menu.Container>
</Menu>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

image

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.

Top comments (0)