27
Passar a escrever os seus componentes no padrão "compound components" pode te salvar muitas horas de refactor.
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
Uma implementação válida poderia ser:
<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.
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,
}
]}
/>
uhuuuul! Esse menu não é mais probl… POW, surge do nada, sem nenhum aviso um novo menu…
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,
},
]} />
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!
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>
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>
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>
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.
27