Implementando um sistema de slots em React para componentes reutilizáveis
Tags: react, webcomponents, javascript, jsx
Published: 2023-06-28 14:05:11

_**Dev coautor @mandado**_

Um dos princípios fundamentais do desenvolvimento de software é a reutilização de código. Ao criar componentes em React, desejamos construí-los de forma modular e flexível, para que possam ser facilmente adaptados e reutilizados em diferentes contextos. Neste artigo, exploraremos a implementação de um sistema de slots em React, que permite a composição de componentes de forma dinâmica e personalizada.

## Entendendo o conceito de slots

Slots são espaços reservados dentro de um componente, nos quais outros componentes ou elementos podem ser inseridos. Eles fornecem um mecanismo flexível para a composição de interfaces, permitindo que partes específicas de um componente sejam personalizadas ou substituídas sem alterar a estrutura geral do componente.

## Implementando o sistema de slots

Vamos começar implementando o componente `Slot`, que será responsável por renderizar os elementos filhos em slots específicos. Veja o código abaixo:

```tsx
import { Children, Fragment, ReactNode, isValidElement } from 'react';

type SlotProps = {
  children: ReactNode;
  name: string;
};

export const Slot = ({ name, children }: SlotProps) => {
  const elements = Children.toArray(children).filter(child => {
    if (isValidElement(child)) {
      return child.type.toString().includes(`slot: "${name}"`) || child?.props?.slot === name;
    }

    return false;
  });
  
  return <Fragment>{elements}</Fragment>;
};

```
Neste código, importamos as dependências necessárias do React e, em seguida, definimos o componente `Slot`. Ele recebe duas propriedades: `name`, que representa o nome do slot, e `children`, que são os elementos a serem renderizados dentro do slot.

Dentro do componente `Slot`, utilizamos a função `Children.toArray` para garantir que os elementos filhos sejam tratados como uma matriz. Em seguida, filtramos esses elementos com base na propriedade `slot` de cada um. Aqueles que correspondem ao nome do slot são mantidos na matriz `elements`.

Por fim, retornamos os elementos filtrados encapsulados em um `Fragment`, que é usado para evitar a criação de um nó HTML adicional desnecessário.

## Utilizando o sistema de slots em um componente

Agora que temos o componente `Slot` implementado, podemos usá-lo para criar componentes reutilizáveis e flexíveis. Vamos criar um exemplo de componente chamado `TopAppBar`, que possui três slots: `leading`, `headline` e `trailing`. Veja o código abaixo:

```tsx
import Slot from './slot';
import React, { ReactNode } from 'react';

type TopAppBarProps = {
  children: ReactNode;
};

const TopAppBar = ({ children }: TopAppBarProps) => (
  <header>
    <div>
      <Slot name='leading'>{children}</Slot>
    </div>
    <div>
      <Slot name='headline'>{children}</Slot>
    </div>
    <div>
      <Slot name='trailing'>{children}</Slot>
    </div>
  </header>
);

export default TopAppBar;
```

Neste exemplo, importamos o componente Slot e o utilizamos dentro de `TopAppBar`. Cada `Slot` é definido em um elemento `div`, com um nome específico passado como propriedade. O conteúdo personalizado para cada `slot` é definido dentro das tags de abertura e fechamento do componente `TopAppBar`.

## Compondo componentes usando slots

Agora que temos nosso componente `TopAppBar` com slots definidos, podemos utilizá-lo em nosso aplicativo e personalizá-lo de acordo com nossas necessidades. Veja o exemplo abaixo:

```tsx
import TopAppBar from './topappbar';

const App = () => (
  <TopAppBar>
    <h1 slot='headline'>Hello World</h1>
  </TopAppBar>
);

export default App;
```

Neste exemplo, importamos o componente `TopAppBar` e o utilizamos no componente `App`. Dentro do `TopAppBar`, especificamos que o componente `<h1>` deve ser renderizado no slot `headline` usando a propriedade `slot`.

## Conclusão

Neste artigo, exploramos a implementação de um sistema de slots em React, permitindo a criação de componentes reutilizáveis e flexíveis. Através do componente `Slot`, conseguimos definir espaços reservados dentro de um componente onde outros componentes ou elementos podem ser inseridos de forma personalizada.

Com o uso de slots, é possível compor interfaces dinamicamente e adaptá-las de acordo com diferentes contextos. Essa abordagem oferece uma maneira poderosa de criar componentes modulares e extensíveis, promovendo a reutilização de código e facilitando a manutenção do projeto.

Espero que este artigo tenha sido útil para entender e implementar o sistema de slots em React. Ao adotar essa abordagem em seus projetos, você estará criando componentes mais flexíveis e adaptáveis, o que contribui para uma melhor experiência de desenvolvimento e uma arquitetura mais modular.

Obrigado por ler e boa sorte em suas implementações com slots no React!

## Agradecimento

Gostaria de expressar meu sincero agradecimento ao @mandado por sua valiosa ajuda na implementação do componente `Slot`. Sua colaboração foi fundamental e estou muito grato por todo o suporte fornecido.

Obrigado pelo seu tempo e contribuição!