Do AngularJS para React

Para quem muito programou usando AngularJS, a primeira impressão ao se deparar com um componente React pode não ser das melhores. O impacto provavelmente mais significativo é ver JavaScript e HTML dividindo o mesmo espaço. Mas não se deixe levar pelas aparências. O React é bem menos estranho do que a primeira impressão pode sugerir.

Antes de investigar mais a fundo as maiores diferenças entre AngularJS e React, precisamos ter ao menos uma visão geral sobre a estrutura que dá suporte ao React. O código JavaScript que vamos ver num componente React não é suportado nativamente pela linguagem. Outra funcionalidade ainda muito incipiente é o uso de módulos. Para fazer uso desses benefícios, duas ferramentas de desenvolvimento entram em cena: Webpack e Babel.

Webpack

O Webpack entra em cena para que possamos organizar nosso código emmódulos. Por padrão, todas as variáveis e funções são privadas dentro de um módulo. Para que se tornem públicas, precisam ser explicitamente exportadas. O conteúdo exportado torna-se então público e passível de ser importado por outros módulos. Dessa forma, não é mais necessário fazer uso de antigas estratégias como IIFE (Immediately Invoked Function Expression) para desfrutar de Closures e prevenir que o escopo global seja acidentalmente poluído com variáveis ou funções indesejadas.

Em suas configurações, definimos um módulo que será o ponto de partida (entry point). O Webpack empacotará os módulos importados pelo ponto de partida, bem como todos os demais módulos importados pelos módulos subsequentes. Através de uma longa varredura, módulo a módulo, o Webpack cria uma árvore de dependências e as conecta num único arquivo chamado de pacote (bundle).

Como se pode ver na imagem, foram incluídos no pacote todos os módulos necessários para a resolução do entry point. O pacote produzido pelo Webpack contém os módulos index.js (entry point),a.js, b.js e c.js. Como nenhum módulo no caminho da resolução do entry point importou o módulo d.js, ele ficou de fora. Isso é ótimo porque significa que módulos que não são efetivamente usados pela aplicação não são empacotados evitando assim peso desnecessário.

Babel

Comparado ao Webpack, o Babel é bem mais simples de entender. Ele é um transpilador de código e nos permite usar funcionalidades da linguagem JavaScript que ainda não são completamente suportadas pelos browsers. No caso do React, ele vai um pouco além e, através de um preset exclusivo, torna possível a utilização de HTML dentro do código JavaScript. Essa sintaxe é popularmente chamada de JSX.

Nesse repositório, você pode conferir os arquivos de configuração .babelrc e webpack.config.js contendo apenas o que é minimamente necessário para empacotar e executar uma aplicação React.

Template Engine

É no HTML que as maiores diferenças entre AngularJS e React são percebidas. Bindings, laços de repetição e renderização condicional funcionam de maneira radicalmente diferentes no React.

Bindings

No AngularJS, o binding é praticado em via de mão dupla. Através da diretiva ng-model, o AngularJS vincula uma variável do controller ao template e vice-versa. Quando essa variável tem seu valor alterado no controller, a mudança se reflete automaticamente no template, e quando o usuário altera o valor dessa variável no template, esta tem seu valor automaticamente atualizado no controller. Além disso, um componente filho pode também alterar o valor da propriedade recebida de seu pai. Dessa forma, tanto o componente pai pode alterar o valor de uma propriedade passada ao componente filho, como também o componente filho pode alterar o valor de uma propriedade passada pelo componente pai. Esse conceito, chamado Two-Way Data Binding, não existe no React.

No React, a via é de mão única, One-Way Data Binding. O valor de uma variável presente no controller se reflete automaticamente no template, mas quando esse valor é alterado no template, esta não tem seu valor automaticamente atualizado no controller. Você precisa atualizá-la manualmente. O valor das propriedades de um componente também só podem ser atualizadas de cima para baixo, ou seja, na direção do componente pai para o componente filho. Um componente não pode alterar o valor de uma propriedade recebida do componente pai.

Playground online: Two-Way Data Binding, One-Way Data Binding.

Renderização Condicional

Era também através de uma outra diretiva do AngularJS que partes de um componente poderiam ser condicionalmente renderizadas. Ou seja, bastava passar à diretiva ng-if um valor trueou false para determinar se aquele elemento e seus eventuais filhos seriam ou não renderizados.

No React, essas condições são escritas com recursos da própria linguagem JavaScript: if statements, operadores ternários ou operadores lógicos &&.

Playground online: Ng-if, If Statement, Operador &&, Operador Ternário.

Laços de Repetição

Da mesma maneira que a renderização condicional, laços de repetição que eram feitos utilizando a diretiva ng-repeat no AngularJS são feitos no React através dos recursos da própria linguagem JavaScript, como por exemplo map.

Playground online: Ng-repeat, Map.

Como é possível notar, uma das características que tanto afasta o React do AngularJS é a maneira como o template é percebido. Alguns desenvolvedores costumam ilustrar muito bem essa diferença com a frase: No AngularJS, colocamos JavaScript no HTML. No React, colocamos HTML no JavaScript.

Mas as principais diferenças entre AngularJS e React não se restringem ao template. A API usada para lidar com o ciclo de vida do componente também muda drasticamente.

Lifecycle Hooks

É através dos ganchos (hooks) relacionados ao ciclo de vida de um componente que obtemos as condições necessárias para executar tarefas específicas. Quando uma tarefa só pode ser executada depois que o template do componente já foi renderizado, ela é vinculada ao gancho de inicialização do componente, por exemplo. Se precisamos executar uma tarefa no momento em que o componente é removido do DOM, ou seja, ao ser desmontado ou destruído, a tarefa deve ser vinculada ao gancho que representa o fim da vida do componente.

Inicialização/Montagem

No AngularJS, a inicialização do componente é representada pela função $onInit. Essa é a função que o AngularJS executa no momento em que o componente está totalmente pronto para uso. Ou seja, o template já está renderizado e todos os bindings estão vinculados ao controller.

No React, tarefas que devem ser executadas em momentos específicos do ciclo de vida do componente são passadas para uma função chamada useEffect. Embora não muito intuitivo, o nome da função faz alusão ao termo side effect. Através do useEffect tem-se a garantia que a tarefa só será executada depois da completa montagem do componente.

Playground online: $onInit, useEffect.

Remoção/Desmonte

Da mesma maneira que em certas ocasiões precisamos executar tarefas somente após a completa montagem de um componente, em outras precisamos executar uma tarefa no momento imediatamente anterior ao seu desmonte. Imagine que na inicialização de um componente é adicionado um listener ao document. Esse listener deverá ser obrigatoriamente removido no momento do desmonte do componente. Caso contrário, toda vez que esse componente for inicializado o mesmo listener será novamente adicionado ao document causando a replicação indesejada do comportamento.

No AngularJS, o método do controller que nos oferece a possibilidade de executar uma tarefa imediatamente antes do desmonte do componente se chama $onDestroy.

No React, novamente recorremos à função useEffect. No caso anterior, é passada como parâmetro para useEffect uma função que será executada no momento em que o componente estiver montado por completo. Se for necessário executar uma tarefa no momento imediatamente anterior ao desmonte do componente, essa função deverá retornar uma outra função. É nessa outra função retornada que deverão estar as tarefas a serem executadas imediatamente antes do desmonte do componente.

Playground online: $onDestroy, useEffect.

Como se pode perceber, o componente React não muda tanto quando a aparência de seu código pode sugerir. Uma vez entendidas as diferenças no formato, um programador acostumado a desenvolver componentes com AngularJS não terá dificuldades em criar, a partir de então, componentes utilizando React.