Componentização Avançada
Atomic Design, componentes compostos, API de componentes limpa e variantes com CVA.
Definição
Componentização eficaz segue princípios: Single Responsibility (um componente, uma responsabilidade), Open/Closed (extensível sem modificar), e interface mínima (poucas props obrigatórias). Atomic Design organiza componentes em Atoms (Button, Input), Molecules (FormField = Label + Input + Error), Organisms (LoginForm), Templates, e Pages. CVA (class-variance-authority) gerencia variantes sem if/else.
Problema → Solução
Problema
Componentes com 30 props booleanas (isLarge, isSmall, isPrimary, isSecondary, isDanger...). Props que mudam comportamento de forma imprevisível. Impossível entender o componente sem ler todo o código.Solução
Variantes como strings (variant="primary" | "secondary" | "danger") em vez de booleanos. Compound components para composição flexível. CVA para gerenciar classes de variantes. Slots/children para extensibilidade sem proliferação de props.Dica de entrevista
Tip
A API de um componente é seu contrato com o consumidor. Adicionar prop é fácil; remover é breaking change. Prefira interface mínima — se não tem caso de uso claro, não adicione a prop. "You can always add, never remove."Código
// CVA para variantes sem if/else
import { cva, type VariantProps } from 'class-variance-authority'
const button = cva(
'inline-flex items-center font-medium rounded transition-colors focus:outline-none focus:ring-2',
{
variants: {
variant: {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
danger: 'bg-red-600 text-white hover:bg-red-700',
ghost: 'text-gray-600 hover:bg-gray-100',
},
size: {
sm: 'text-xs px-2 py-1',
md: 'text-sm px-3 py-2',
lg: 'text-base px-4 py-3',
},
},
defaultVariants: { variant: 'primary', size: 'md' },
}
)
interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof button> {}
export function Button({ variant, size, className, ...props }: ButtonProps) {
return <button className={button({ variant, size, className })} {...props} />
}
// Uso
<Button variant="danger" size="lg">Deletar</Button>
<Button variant="ghost">Cancelar</Button>Perguntas de entrevista
Q.Booleano vs string para variantes de componente?▾
A.String é melhor: variant="primary" | "secondary" é auto-documentável, mutuamente exclusivo por definição, e extensível sem breaking change. Booleanos (isPrimary, isSecondary) podem ser combinados de formas inválidas e ficam verbosos com muitas variantes.
Q.O que é o padrão de Compound Components?▾
A.Componentes que cooperam via Context implícito: <Select><Select.Trigger/><Select.Content><Select.Item/></Select.Content></Select>. O pai gerencia estado, filhos consomem via useContext. Radix UI, shadcn/ui e Headless UI usam esse padrão extensivamente.
Q.Como documentar componentes efetivamente?▾
A.Storybook com stories para cada variante e estado (default, hover, focus, disabled, error, loading). Controls para props interativas. Docs automáticos via JSDoc/TSDoc. Testes de acessibilidade com @storybook/addon-a11y. Stories servem como spec executável.
Termos relacionados
62/122← →