Composition Pattern

Mastering React Composition

Are you already using the Composition Pattern in your projects? If not, you should. I'll explain a little why in this post.

In the past, we used to use props to manage components, both visually and in the implementation logic itself.

A common scenario we come across is to build an input field as seen below:

inputexemplo de como geralmente são com múltiplas props


In this model, we are stuck with a confusing implementation and the need to add and maintain a multitude of possible component layout or style changes. It is always necessary to create a new prop or even “slots” to add a new visualization layer to our component.

Well, how can we improve the implementation of this component and make it more user-friendly for us developers?

The first step is to break this component into smaller parts. The composition pattern involves building complex components by combining smaller components, called low-level components or primitive components.

estrutura de um componenteestrutura de um componente

In this folder structure, we can see that the component has been divided into several layers, each isolating responsibility for what the file name indicates. By separating a component into several parts, we have greater control over both visualization and implementation, without having to deal with multiple states in the same file or test all the infinite variations of properties (a burden for developers).

We then move from a concept of “N props” to a more efficient composition. The biggest advantage of this creation model is the ability to decide what you need at the moment, without adding additional logic for organizing the elements. See the example below:

exemplo de uso de um pós refatoraçãoexemplo de uso de um pós refatoração

The biggest advantage of this creation model is really the decision of what you need at that moment or not (besides of course maintenance and construction), for example, an input without the Label component just doesn't render the Input.Label component

<Input.Root>
  <Input.Group>
    <Input.Icon icon={<User color="#999" size={18} />} /> 
    <Input.Input
      placeholder="Seu nome de usuário"
      type="text" {...register("username", { required:true })} 
    />
  </Input.Group>
</Input.Root>

Below is an example that we can make a slightly more complex implementation by just adding a new Icon to the right of the Input without having to add any element organization logic.

adicionando ícones a este componenteadicionando ícones a este componente

In summary, when following this pattern, we have:

  • Clearer components to understand;

  • More focused maintenance;

  • Reuse, avoiding duplication of components and logic;

  • Flexibility when rendering a new component;

  • Abstraction of states within the case itself, without huge files with infinite booleans to control the visualization.

And so on…

What I told you is a little of what I learned, and I certainly may have forgotten something. Feel free to talk to me about this or suggest changes!

See you soon.

reactpatterns