DEV Community

Cover image for React na Prática: Componentes controlados ou não Controlados
Alvaro Guimarães
Alvaro Guimarães

Posted on • Edited on

React na Prática: Componentes controlados ou não Controlados

Controlled vs Uncontrolled

Uma decisão importante que afeta bastante na qualidade do seu código é determinar onde o estado de um componente deve residir, e esta decisão impacta diretamente a flexibilidade, reusabilidade e complexidade.

Um exemplo clássico desta decisão é a implementação de um modal: deve ele gerenciar seu próprio estado de visibilidade ou delegar este controle ao componente pai?

Componentes Controlados: Delegando o Controle

Em um componente controlado, o estado é gerenciado externamente pelo componente pai.

Esta abordagem oferece maior flexibilidade e permite que o componente pai coordene múltiplos estados relacionados.

Nessa abordagem, podemos dizer que a flexibilidade do Modal é alta, mas a
responsabilidade sobre ele também é, pois, o componente pai precisa manter a lógica necessária para abrir e fechar o modal.

// Exemplo de Modal controlado:
export function Modal({ isOpen, onChangeIsOpen, children }) {
  // O componente recebe o estado como prop e delega mudanças através de callbacks
  return (
    <dialog 
      open={isOpen}
      onClose={() => onChangeIsOpen(false)}
    >
      {children}
    </dialog>
   );
}

// Exemplo de uso:
export function App() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div>
      <Modal isOpen={isOpen} onChangeIsOpen={setIsOpen}>
        <p>Greetings, one and all!</p>
        <button onClick={() => setIsOpen(false)}>OK</button>
      </Modal>
      <button onClick={() => setIsOpen(true)}>Open Modal</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Componentes Não Controlados: Autonomia Interna

Por outro lado, componentes não controlados mantêm e gerenciam seu próprio estado internamente. Esta abordagem reduz a complexidade do componente pai e é ideal quando o comportamento do componente pode ser encapsulado de forma independente.

// Exemplo de modal não controlado:
export function Modal({ children, onOpenChange }) {
  const [isOpen, setIsOpen] = useState(false);

  const handleOpenChange = (newState) => {
    setIsOpen(newState);
    onOpenChange?.(newState); // Opcional: notifica o pai sobre mudanças
  };

  if (!isOpen) { 
    return (
      <button onClick={() => handleOpenChange(true)}>Open Modal</button>
    );
  }

  return (
    <dialog 
      open
      onClose={() => handleOpenChange(false)}
    >
      {children}
      <button onClick={() => handleOpenChange(false)}>OK</button>
    </dialog>
   );
}

// App.tsx
function App() {
  return (
    <Modal onOpenChange={(isOpen) => console.log('Modal state:', isOpen)}>
      <p>Greetings, one and all!</p>
    </Modal>
  );
}
Enter fullscreen mode Exit fullscreen mode

Esta decisão de design influencia diretamente a manutenibilidade e reusabilidade do seu código.

Use componentes controlados quando:

  • O componente pai precisa coordenar múltiplos estados relacionados
  • Você precisa de controle preciso sobre o comportamento do componente
  • O estado do componente precisa ser sincronizado com outras partes da aplicação

Use componentes não controlados quando:

  • O comportamento do componente é independente do resto da aplicação
  • Você quer reduzir a complexidade do componente pai
  • O componente pode funcionar de forma autônoma

Top comments (0)