DEV Community

Matheus
Matheus

Posted on

Padrão de design de componentes agnósticos

Esse padrão visa criar componentes desacoplados de bibliotecas específicas, definindo uma camada de abstração que permite a
integração com diferentes frameworks ou bibliotecas de UI, como React, Vue, ou Angular, ou mesmo diferentes bibliotecas de UI dentro de um mesmo framework, como PrimeReact, Material-UI, etc.

Requisitos

Para aplicar este padrão, não é necessário definir todos os componentes de uma vez, o processo pode ser progressivo, sendo aplicado, conforme a necessidade de utilização de novos componentes.

Organização de pastas e arquivos

Por prefêrencia pessoal, costumo disponibilizar os componentes agnósticos, na camada de UI compartilhada para aplicação,
geralmente é a camada, onde ficam os types, interfaces, styles, layouts, e utils.

Uma forma de organização de pastas, aplicando os conceitos de camadas, pode ser como a sugerida abaixo:

── src
    └── shared
        └── common
            └── ui
                └── components
                    └── Button
                        ├── Button.interface.ts
                        ├── Button.tsx
                        └── PrimeReactButton.component.tsx
Enter fullscreen mode Exit fullscreen mode

É uma forma de organizar os componentes de forma que fique explícito que são compartilhados para aplicação inteira.

Implementação

Explicação sobre cada arquivo e como serem utilizados.

Button.interface.ts - Este arquivo define a interface TypeScript para o componente Button.
Ele descreve os tipos das propriedades (props) que o componente Button aceita.
A interface ajuda a garantir que o uso do componente seja seguro e consistente,
facilitando a tipagem forte no TypeScript.

export interface ButtonPropsInterface {
    label: string;
    onClick: () => void;
    disabled?: boolean;
    type?: 'button' | 'submit' | 'reset';
}

Enter fullscreen mode Exit fullscreen mode

Button.tsx - Este arquivo contém a implementação genérica do componente Button em React.
Ele representa um botão "agnóstico", e atua como um wrapper que incorpora a lógica do botão e delega a renderização a um
adaptador,
que neste caso é o PrimeReactButtonComponent.

import React from "react";
import { ButtonPropsInterface } from "@/shared/common/ui/components/Button/Button.interface";
import PrimeReactButtonComponent from "@/shared/common/ui/components/Button/PrimeReactButton.component";

const Button: React.FC<ButtonPropsInterface> = ({label, onClick, disabled, type = 'button'}) => {
    return (
        <PrimeReactButtonComponent type={type} onClick={onClick} disabled={disabled}>
            {label}
        </PrimeReactButtonComponent>
    );
};

export default Button;
Enter fullscreen mode Exit fullscreen mode

PrimeReactButton.component.tsx - Este arquivo contém a implementação específica do componente Button utilizando a
biblioteca PrimeReact. Ele serve como um adaptador que adapta a interface genérica do botão para usar o componente específico do PrimeReact, mantendo a mesma interface definida no arquivo Button.interface.ts. Assim, ele traduz as propriedades genéricas para a implementação específica da biblioteca.

import { ButtonProps } from './Button.interface';
import { Button as PrimeButton } from 'primereact/button';

const PrimeReactButtonComponent: React.FC<ButtonProps> = ({label, onClick, disabled, type = 'button'}) => {
    return (
        <PrimeButton label={label} onClick={onClick} disabled={disabled} type={type}/>
    );
};

export default PrimeReactButtonComponent;

Enter fullscreen mode Exit fullscreen mode

Utilização

Onde for utilizar, basta realizar a importação do componente agnóstico:

import Button from "@/shared/common/ui/components/Button/Button";
Enter fullscreen mode Exit fullscreen mode

E realizar o uso normalmente, passando as propriedades obrigatórias e opcionais, caso desejado:

<Button
    label="Voltar"
    icon="pi pi-angle-left"
    severity="secondary"
    onClick={() => router.push("/home")}
/>
Enter fullscreen mode Exit fullscreen mode

Troca de bibliotecas

Se for necessário um dia trocar a biblioteca, basta criar um adaptador que realize a implementação especifica da biblioteca,
e trocar na implementação genérica do componente pelo adaptador novo.

Top comments (0)