Não há dúvida de que os componentes são uma abstração poderosa para criar interfaces de usuário front-end (e, ao que parece, IUs baseadas em texto , aplicativo roteadores e muitos outros tipos de interfaces).
Mas existem muitas abordagens diferentes para os componentes de criação. Nesta postagem, falaremos sobre o padrão de componente composto e quando ele pode ser uma escolha apropriada para autores de componentes.
O que são componentes compostos?
Componentes compostos são grupos de componentes individuais que se unem para criar um comportamento coeso e complexo. Eles trabalham juntos, compartilhando o estado dos bastidores, para oferecer uma sintaxe intuitiva e expressiva para o programador que está usando os componentes. Um dos exemplos mais familiares de componentes compostos vem do HTML vanilla:
Neste exemplo, os elementos e
se juntam para formar um controle de entrada complexo que é familiar para muitos usuários. O
mantém seu próprio estado interno para o qual
é atualmente selecionado pelo usuário e fornece comportamentos avançados como entrada de teclado para alterar a opção
.
Como implementar componentes compostos
Primeiro, certifique-se de que um componente composto seja o design de API apropriado. Como qualquer paradigma de programação, os componentes compostos vêm com sua cota justa de compensações. Geralmente, qualquer padrão onde há um estado compartilhado implícito-ou comportamento que é”mágico”ou não facilmente detectável-pode causar dores de cabeça no futuro se não for projetado com o máximo cuidado.
Algumas perguntas a se fazer antes de projetar um componente composto são:
- O programador que usa o componente realmente precisa compor dois (ou mais) componentes para obter o resultado desejado? Ou o mesmo resultado pode ser alcançado com um design de componente único mais simples e entradas ou adereços apropriados?
- As interações e funções entre os componentes serão claras e intuitivas para os programadores que os utilizam?
Considere cuidadosamente as várias APIs para seu novo componente e consulte os colegas sobre qual API eles preferem consumir.
Aqui estão alguns exemplos de paradigmas de IU comuns que se adaptam bem ao padrão de componente composto:
- Um componente de tabela avançado que permite aos usuários do componente fornecer não apenas os dados tabulares, mas também classificação personalizada ou comportamento de filtragem
- Um componente suspenso pesquisável onde os usuários do componente fornecerão as opções
Arquitetura de componentes compostos no React
Para implementar nossos componentes compostos de exemplo no React, iremos alavancar uma série de APIs do React, portanto, um conhecimento básico de cada um será útil:
- Ganchos e componentes funcionais
- API de contexto para compartilhar o estado entre os componentes
Construindo um componente composto
Vamos construir um rascunho de um componente composto que permite ao usuário selecionar várias opções de uma lista, usando um campo de texto para filtrar a lista, se desejar.
Implementação de subcomponentes e um componente de App
Para criar nosso componente composto, implementaremos dois subcomponentes:
-
EnhancedMultiSelect
: este será o componente de embalagem externa e terá as seguintes funções:- Encapsular o estado das opções filho
- Renderize o campo de texto para opções de filtragem
-
EnhancedMultiSelectOption
: este componente expressará as opções individuais selecionáveis e terá as seguintes funções:- Ler e gravar no estado de seleção com base na interação do usuário
- Leia o valor do filtro e exclua-se da renderização, se apropriado
Por fim, também implementaremos um componente App
que usa nosso componente composto para desenvolver e testar sua API.
EnhancedMultiSelect
Primeiro, criaremos um contexto que será usado para compartilhar o estado entre os componentes pai e filho.
exportar const EnhancedMultiSelectContext=createContext ();
A seguir, implementaremos a assinatura para nosso componente, o que levará três adereços:
-
children
: os filhos na árvore de renderização, que incluirão as opções selecionáveis e qualquer outra marcação exigida pela IU. Não nos importamos com o quão profundamente aninhadas as opções aparecem ou se existem outros componentes na árvore, permitindo flexibilidade de uso para o engenheiro que está usando nosso componente -
value
: umConjunto
de strings representando as opções selecionadas -
onChange
: uma função que chamaremos com um novoSet
sempre que a seleção mudar
função padrão de exportação
EnhancedMultiSelect ({children, value, onChange}) {}
Agora vamos implementar o corpo do nosso componente. Primeiro, usaremos um gancho useState
para rastrear a consulta que o usuário digitou na entrada de texto do filtro.
const [filtro, setFilter]=useState ('');
Em seguida, retornaremos os componentes que o React renderizará para nós. Primeiro, vamos configurar um provedor para o contexto que configuramos anteriormente e usá-lo para fornecer alguns valores que serão usados pelas opções mais tarde:
- Uma função
isSelected
que pega uma chave de string e retorna se a chave fornecida aparece ou não na seleção - Uma função
setSelected
que pega uma chave e adiciona ou remove a chave da seleção conforme indicado - O valor atual da entrada de texto do filtro
Também renderizaremos nossa entrada de texto de filtro e os componentes filhos dentro do provedor de contexto. Aqui está o código-fonte completo para EnhancedMultiSelect
:
import {createContext, useState} de'react'; exportar const EnhancedMultiSelectContext=createContext (); função padrão de exportação EnhancedMultiSelect ({children, value, onChange}) { const [filtro, setFilter]=useState (''); Retorna (value.has (key), setSelected: (chave, selecionado)=> { const newValue=new Set ([... valor]); if (selecionado) { newValue.add (chave); } outro { newValue.delete (chave); } onChange (newValue); }, filtro, }} > setFilter (evt.target.value)} /> {crianças} ); }
EnhancedMultiSelectOption
Agora, implementaremos a outra metade do nosso componente composto, que exigirá dois acessórios:
-
children
: para exibir tudo o que o usuário de nosso componente gostaria de renderizar dentro da opção selecionável -
valor
: uma string para representar esta opção; se esta opção for selecionada, este valor será incluído noConjunto
exposto pelo componente paiEnhancedMultiSelect
função padrão de exportação EnhancedMultiSelectOption ({children, value}) {}
A primeira coisa que faremos no corpo do nosso componente é consumir o contexto fornecido pelo componente pai EnhancedMultiSelect
, usando atribuição de desestruturação para separar o contexto para uso mais fácil.
const {isSelected, setSelected, filter}=useContext ( EnhancedMultiSelectContext, );
Agora que temos a consulta de filtro do usuário do contexto, se ela não corresponder ao valor da opção, retornaremos null
para não renderizar:
if (! value.includes (filter)) { return null; }
Por fim, renderizaremos a caixa de seleção e conectaremos seu estado marcado
ao estado de seleção de nosso componente composto, bem como quaisquer filhos que o consumidor de nosso componente gostaria de renderizar. Aqui está o código-fonte completo para EnhancedMultiSelectOption
:
import {useContext} de'react'; import {EnhancedMultiSelectContext} de'./EnhancedMultiSelect'; função padrão de exportação EnhancedMultiSelectOption ({children, value}) { const {isSelected, setSelected, filter}=useContext ( EnhancedMultiSelectContext, ); if (! value.includes (filter)) { return null; } Retorna ( ); }
App
Para ver como tudo funciona junto, consumiremos nosso componente composto e o renderizaremos em um componente App
de ponto de entrada:
import {useState} de'react'; importar EnhancedMultiSelect de'./EnhancedMultiSelect'; importar EnhancedMultiSelectOption de'./EnhancedMultiSelectOption'; função padrão de exportação App () { const [seleção, setSelection]=useState (new Set ()); Retorna (setSelection (v)}> Maçãs Laranjas Pêssegos Uvas Ameixas {JSON.stringify ([... seleção], nulo, 2)}
);
}Arquitetura de componente composto em Angular
Vamos construir o mesmo componente composto simples usando a estrutura Angular .
enhanced-multi-select.component.ts
Para o componente externo, vamos configurar um modelo simples que contém uma entrada de texto com uma ligação bidirecional para a propriedade
filtro
. Como no exemplo React, criaremos uma entrada para o estado de seleção e uma saída quando o estado de seleção mudar. Aqui está o código-fonte completo:import {Component, Input, Output, EventEmitter} de'@ angular/core'; @Componente({ seletor:'app-Enhanced-multi-select', template: ``, }) export class EnhancedMultiSelectComponent { @Entrada() valor !: Definir ; @Resultado() valueChange=new EventEmitter > (); filtro=''; }
enhanced-multi-select-option.component.ts
Para os itens de opção, renderizaremos um rótulo que envolve a caixa de seleção e o conteúdo do componente, assim como no exemplo React. Usaremos o sistema de injeção de dependência do Angular para obter uma referência ao pai
EnhancedMultiSelectComponent
instância passada por meio doconstrutor
.Com essa referência, podemos avaliar e manipular o estado diretamente e verificar se a opção deve ser visível de acordo com o valor da string de filtro fornecida pelo usuário. Aqui está o código-fonte:
import {Component, Input} de'@ angular/core'; import {EnhancedMultiSelectComponent} de'./enhanced-multi-select.component'; @Componente({ seletor:'opção de seleção múltipla aprimorada pelo aplicativo', template: ` `, }) export class EnhancedMultiSelectOptionComponent { construtor (seleção privada somente leitura: EnhancedMultiSelectComponent) {} visível() { return this.value.includes (this.select.filter); } selecionado() { retornar this.select.value.has (this.value); } setSelected (selected: boolean) { if (selecionado) { this.select.value.add (this.value); } outro { this.select.value.delete (this.value); } } @Entrada() valor !: string; }
app.component.ts
Finalmente, usaremos nosso componente composto e exibiremos os dados de seleção JSON formatados para fins de demonstração:
import {Component} de'@ angular/core'; @Componente({ seletor:'app-root', template: `Maçãs Laranjas Pêssegos Uvas Ameixas {{selectionArray () | json}}
`,
})
export class AppComponent { seleção=novo Set(); selectionArray () { return [... this.selection]; }
}Conclusão
Nesta postagem, implementamos um componente composto de seleção múltipla filtrável no React, usando o API de contexto e em Angular, usando injeção de dependência .
Os componentes compostos são uma opção para criar uma API simples para compor um comportamento muito complexo para um único componente. Existem muitos padrões alternativos, como “render adereços” em React, e as compensações de cada padrão devem ser cuidadosamente consideradas para um caso de uso específico.
O código-fonte completo para executar os exemplos acima em um ambiente de desenvolvimento pode ser encontrado em GitHub .
A postagem Criando componentes compostos em React e Angular apareceu primeiro no LogRocket Blog .