Site menu Programação reativa
e-mail icon
Site menu

Programação reativa

e-mail icon

2018.07.10

Este artigo expressa a opinião do autor na época da sua redação. Não há qualquer garantia de exatidão, ineditismo ou atualidade nos conteúdos. É proibida a cópia na íntegra. A citação de trechos é permitida mediante referência ao autor e este sítio de origem.

A programação reativa, nome derivado do framework React, é um conceito que tem ganhado aceitação crescente no desenvolvimento de interfaces de usuário (UIs), tanto na Web (o Vue.js, principal concorrente do React, também é reativo) como fora dela (React Native, Flutter).

O conceito

Como toda boa ideia, o conceito central é simples, óbvio até (em retrospecto). Suponha uma página Web gerada com base num template, mais algumas propriedades dinâmicas. Se alguma propriedade muda, a página inteira é gerada novamente. Simples assim!

Parece ineficiente, mas o React saiu-se com uma otimização curiosa. A fase mais "cara" de atualizar uma página Web é mexer na DOM. Num framework reativo, apenas as diferenças entre páginas nova e velha são aplicadas na DOM. Talvez isto ainda seja um pouco menos eficiente do que atualizar explicitamente a DOM apenas nos lugares exatos, porém o ganho de produtividade no desenvolvimento compensa de longe.

No desenvolvimento convencional, é preciso de alguma forma monitorar mudanças nas propriedades e invocar a atualização de UI de acordo. Os frameworks reativos fazem uso de alguns truques para que este monitoramento seja automático. A página reage automaticamente às mudanças — efeito que batiza o framework React, e o conceito.

A própria reatividade permite outra otimização: quando uma propriedade é alterada, reagem apenas os componentes dependentes dela. Assumindo que a página Web seja desenvolvida segundo uma hierarquia de componentes, tipicamente a mudança de uma propriedade afeta uma "área" muito pequena da página, e a comparação nova/velha só precisa trabalhar sobre um pequeno pedaço da DOM.

Programação funcional

A reatividade permite tirar da estante a programação funcional. Uma função pura é aquela cujo resultado depende apenas dos argumentos. Por exemplo, podemos confiar que abs(-3) é sempre igual a 3. Por outro lado, o resultado de fopen("arquivo.txt") depende de fatores externos.

Num framework reativo, o estado da UI é uma função pura das propriedades, e o estado da UI é sempre consistente em relação às propriedades. O desenvolvedor ocupa-se de "o que deve ser mostrado", não de "como mostrar".

Um enorme desafio na programação de UI típica é manter o sincronismo entre o estado interno do aplicativo e aquilo que é mostrado na tela. É muito fácil trocar os pés pelas mãos. A reatividade elimina esta preocupação.

One-way binding

Para que a UI seja função pura das propriedades, a UI nunca deve alterar a si mesma diretamente. Suponha que o nome de um botão deva mudar quando ele é pressionado. Tipicamente, fazemos isso no próprio tratador de evento de clique. Já num framework reativo, o tratador de evento deve apenas alterar uma propriedade, de que o nome do botão dependa. É o conceito de one-way binding.

Como as alterações fluem exclusivamente em uma direção, outro problema típico de programação UI deixa de acontecer: os famigerados loops infinitos, quando um tratador de evento modifica a UI, disparando outro tratador, que modifica a UI de novo e assim por diante. Óbvio que ainda é possível "fabricar" um loop infinito de forma reativa, mas a chance disso acontecer acidentalmente é menor.

O React leva isso às últimas conseqüências. Até mesmo a digitação dentro de um campo de formulário é bloqueada, pois a rigor ela altera a DOM; o React detecta e desfaz cada alteração. Para que um campo seja "preenchível", é preciso tratar os eventos de teclado, manipular alguma propriedade com base neles, e essa propriedade preenche reativamente o atributo value do campo.

É uma opção polêmica. Por um lado, a abordagem do React garante consistência absoluta. Por outro lado, ela anula a implementação do browser, e parece uma interferência excessiva — afinal, campos foram feitos para serem preechidos, certo? Outros frameworks, até mesmo o Vue.js, implementam two-way binding e permitem o preenchimento "natural" de um campo, cujo valor pode refletir automaticamente numa propriedade (reatividade inversa).

Propriedades, dados internos e estado

Até aqui temos dito que a UI é função pura de propriedades, mas é interessante expandir um pouco essa nomenclatura.

Pelo menos no linguajar React/Vue.js, propriedades ou "props" são parâmetros imutáveis de um componente de UI. Um componente-pai passa propriedades a um componente-filho. Se o pai deseja filhos com propriedades diferentes, deve gerar novos filhos, pois a "geração" anterior é imutável.

Um componente pode possuir dados internos mutáveis. Por exemplo, um componente-relógio precisa no mínimo da hora atual, atualizada por um timer. De acordo com a "doutrina reativa", tais dados só dizem respeito ao próprio componente, e não devem ser compartilhados com outros componentes, exceto na forma de propriedades passadas aos componentes-filhos.

O estado da aplicação é análogo ao Modelo da arquitetura MVC. É um dicionário de dados que não pertence a nenhum componente em especial. É a parte mais importante da aplicação, pois presumivelmente toda a UI, bem como as propriedades e dados internos dos componentes, são em última instância derivados do estado.

Por ser tão importante, o estado costuma ser mantido por algum framework específico (Redux, Vuex) em vez de ser uma simples matriz associativa.

Nem sempre é fácil saber se um determinado valor deve ser alocado como propriedade, dado ou estado. Por exemplo, um componente-relógio poderia alocar a hora atual das três formas, e funcionaria bem em qualquer caso. Se o relógio é apenas um adorno na tela, faz mais sentido que seja um dado interno do componente. Mas se a hora exibida por ele tem significado especial (por exemplo, o usuário dispara um processo num momento exato) pode ser o caso da hora atual ficar no estado da aplicação. Também seria o caso da hora ficar no estado se a UI exibir vários relógios, a fim de que todos fiquem sincronizados. Por outro lado, dificilmente seria uma boa ideia passar a hora atual como propriedade (imutável) do componente. Até funcionaria, mas o componente-relógio teria de ser recriado a cada segundo.

JSX versus templates

Todo desenvolvedor é doutrinado "desde criancinha" a trabalhar em camadas independentes. No caso de desenvolvimento front-end Web, as camadas são HTML (semântica), CSS (aparência visual) e Javascript (código). Frameworks como Angular seguem esta divisão: cada componente tem pelo menos três arquivos-fonte.

O React subverteu esta lógica. Um componente React é 100% Javascript e só precisa de um arquivo-fonte. Ele gera código HTML usando Javascript e encoraja a geração dinâmica de CSS (embora isto exija um framework independente do React base). Não há templates. As justificativas são boas:

O React oferece o JSX, um dialeto de Javascript que suporta HTML diretamente no código, lembrando o PHP. É outro recurso polêmico, com apaixonados defensores e detratores. Alguns atribuitos HTML são renomeados no JSX por conflitarem com palavras-chave Javascript, ou por variarem entre browsers. Então poder-se-ia alegar que o "HTML" embutido no JSX é na verdade uma DSL disfarçada. Outra crítica válida é a maior dificuldade de delegar o design Web a não-desenvolvedores.

Pessoalmente, não gostei muito do JSX porque a mistura HTML/JS não é totalmente livre. Apenas expressões são aceitas; não é possível entremear estruturas de controle. Por exemplo, para gerar um bloco HTML dentro de um loop, é preciso criar uma função auxiliar que contém o HTML. Se se é obrigado a confinar o HTML aqui e ali, me parece melhor confiná-lo todo a um template de uma vez.

O Vue.js parece ter atingido um equilíbrio nestas questões. Um componente pode ser implementado num único arquivo-fonte, e dentro dele há seções separadas de template, código e CSS (cujo escopo pode ser restrito ao componente). A DSL de template do Vue.js é simples e ergonômica; é talvez a parte mais fácil de aprender.

e-mail icon