7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
Advertisement
  1. Code
  2. Web Development

Introdução à Framework de React

Read Time: 18 mins

Portuguese (Português) translation by Claudia Conceicao (you can also view the original English article)

No mundo actual de frameworks de Aplicações Javascript, a filosofia de desenvolvimento é um fator-chave diferenciador. Se comparares as frameworks populares de JS, como EmberJS, AngularJS, Backbone, Knockout, etc. de certeza que vais encontrar diferenças nas suas abstrações, no modelo de pensamento, e claro na terminologia. Isto é uma consequência direta da filosofia de desenvolvimento estrutural. Mas, em princípio, todas elas fazem uma coisa, que é abstrair o DOM de tal forma que não lidas diretamente com os elementos HTML.

Pessoalmente penso que uma framework se torna interessante quando disponibiliza um conjunto de abstrações que permitem uma forma diferente de pensar. Neste aspeto, react, a nova framework de JS da equipa do facebook, vai forçar-te a repensar (de certa maneira) como decompões a IU e as interações da tua aplicação. Tendo atingido a versão 0.4.1 (assim como este texto), React disponibiliza um surpreendentemente simples, mas eficaz modelo para construir aplicações JS que combinam um agradável cocktail de outra natureza.

Neste artigo, vamos explorar os blocos de construção do React e adotar um estilo de pensamento que à primeira pode parecer contraditório. Mas, como a documentação React refer: "Dá-lhe Cinco Minutos" e verás como esta abordagem se tornará mais natural.

Motivações

A história do React começou dentro do Facebook, onde foi preparado por algum tempo. Ao atingir um estado suficientemente estável, os programadores decidiram torná-lo acessível há alguns meses. Curiosamente o website do Instagram também é movido pela framework React.

O React aborda o problema da abstração do DOM de uma forma ligeiramente diferente. Para perceber como isto é diferente, vamos ignorar brevemente as técnicas adotadas pelas frameworks que mencionei anteriormente.

Uma perspetiva geral de nível elevado das Frameworks de Aplicações JS

O padrão de desenvolvimento MVC (Modelo-Vista-Controlador) é fundamental para o desenvolvimento de IU, não só em aplicações web, mas também em aplicações front-end para qualquer plataforma. No caso das aplicações web, o DOM é a representação física de uma Vista. O próprio DOM é gerado a partir de um template textual de html que é puxado de um ficheiro diferente, de um bloco de código ou de uma função pré-compilada de um template. A Vista é uma entidade que torna o template textual num fragmento do DOM. Ela também define manipuladores de eventos e ocupa-se de manipular o DOM como sendo parte do seu ciclo de vida.

Para a Vista ser útil, precisa de mostrar alguma informação, e possivelmente permitir interação do utilizador. A informação é o Modelo, que vem de alguma fonte de informação (a base de dados, serviço web, armazenamento local, etc.). As frameworks disponibilizam uma forma de 'ligar' a informação à vista, de tal forma que as alterações da informação são automaticamente refletidas com alterações na vista. Este processo automático é chamado de ligação de dados e existem APIs/técnicas para fazer isto tão dinamicamente quanto possível.

A tríade MVC completa-se com o Controlador, que envolve a Vista e o Modelo e coordena o fluxo de informação (Modelo) na Vista e eventos de utilizador fora da Vista, que possivelmente geram alterações no Modelo.

mvc-flowmvc-flowmvc-flow

As frameworks que automaticamente tratam do fluxo de informação para frente e para trás entre a Vista e o Modelo mantêm um evento loop interno. Este evento loop é necessário para escutar alguns eventos de utilizador, eventos de alteração de informação, estímulos externos, etc e determina se há alguma alteração relativamente ao ciclo anterior. Se houver alterações, em qualquer extremidade (Vista ou Modelo), a framework assegura que ambos são sincronizados.

O que faz o React ser Diferente?

Com React, a parte da Vista da tríade MVC assume proeminência e é integrada numa entidade chamada Componente. O Componente mantém um conjunto imutável de propriedades chamado props, e um estado que representa um estado da IU orientado ao utilizador. A parte do Componente que produz a vista é muito interessante e possivelmente a razão pela qual o React se destaca comparando com outras frameworks. Ao invés de construir um DOM físico diretamente de um template de ficheiro/script/função, o Componente gera um DOM intermédio que é um substituto do DOM HTML real. Um passo adicional é depois feito para traduzir este DOM intermédio em DOM HTML real.

Como parte da produção do DOM intermédio, o Componente também atribui manipuladores de eventos e liga a informação contida nas props e no estado.

Se a ideia de um DOM intermédio soa um pouco estranha, não fiques preocupado. Já viste esta estratégia ser adotada por linguagens dinâmicas (aka Máquinas Virtuais) para linguagens interpretadas. O tempo de execução do nosso Javascript, primeiro gera uma representação intermédia antes de lançar o código nativo. Isto também é verdade para outras linguagens baseadas em máquinas virtuais como Java, C#, Ruby, Python, etc.

O React adota inteligentemente esta estratégia para criar um DOM intermédio antes de gerar o DOM HTML final. O DOM intermédio é apenas um objeto gráfico de JavaScript e não é renderizado diretamente. Este é o passo de tradução que cria o DOM real. Esta é a técnica subjacente que faz o React fazer rápidas manipulações do DOM.

O React em Profundidade

Para ter uma melhor ideia de como o React faz tudo funcionar, vamos aprofundar um pouco mais; começando com o Componente. O Componente é o primeiro bloco de construção no React. Podes compôr a IU da tua aplicação compondo um esquema de Componentes. Cada Componente fornece uma implementação para o método render(), onde cria o DOM intermédio. Chamar React.renderComponent() no componente origem resulta em repetidamente percorrer o esquema de componentes e construir o DOM intermédio. O DOM intermédio é depois convertido no DOM HTML real.

component-dom-treecomponent-dom-treecomponent-dom-tree

Já que a criação do DOM intermédio é uma parte integral do Componente, o React fornece uma extensão útil de XML para JavaScript, chamada JSX, para construir o esquema de componentes como um conjunto de nós XML. Isto faz com que seja mais fácil visualizar e racionalizar sobre o DOM. O JSX também simplifica a associação de manipuladores de eventos e propriedades como atributos xml. Sendo que o JSX é uma linguagem de extensão, existe uma ferramenta (linhas de comandos e no browser) para gerar o JavaScript final. Um nó XML de JSX liga-se diretamente a um Component. Vale a pena referir que o React funciona independentemente do JSX e a linguagem JSX apenas torna fácil criar um DOM intermédio.

Ferramentas

A estrutura base do React pode ser descarregada a partir do website deles. Adicionalmente, para a transformação JSX -> JS, podes usar ou o JSXTransformer no browser ou a linha de comandos, chamada react-tools (instaladas via NPM). Irás precisar do Node.js instalado para a descarregares. A ferramenta da linha de comandos permite-te pré-compilar os ficheiros de JSX e evitar a tradução no browser. Isto é definitivamente recomendado se os teus ficheiros de JSX são grandes ou muitos em número.

Um simples componente

Muito bem, temos visto muita teoria até agora, e estou certo de que estás ansioso para ver código real. Vamos ver o nosso primeiro exemplo:

Embora simples, o código acima abrange uma boa parte da área de superfície do React:

  • Criamos o component Simple usando React.createClass e passando-lhe um objeto que implementa algumas funções essenciais. A mais importante é a render(), que gera o DOM intermédio.
  • Estamos a usar JSX para definir o DOM e atribuimos o manipulador do evento de premir rato. A sintaxe {} é útil para incorporar expressões JavaScript para atributos (onMouseDown={this.handleClick}) e nós filhos (<span class="count"> {this.state.count}</span>). Os manipuladores de eventos associados usando a sintaxe {} são automaticamente vinculados à instância do componente. Assim this dentro da função de manipulação de eventos refere-se à instância do componente. O comentário na primeira linha /** @jsx React.DOM */ é uma sugestão para o transformador JSX fazer a tradução para JS. Sem esta linha de código, não irá ocorrer tradução.

Podemos correr a ferramenta de linha de comandos (jsx) no mode de vigia e auto compilar alterações de JSX -> JS. Os ficheiros de origem estão na pasta /src e o output é gerado na /build.

Aqui está o ficheiro JS gerado:

Repara como as tags <div/> e <span/> mapeam as instâncias de React.DOM.div e React.DOM.span.

  • Agora voltemos ao nosso código exemplo. Dentro de handleMouseDown, usamos this.props para ler a propriedade mensagem que foi passada. Definimos a mensagem na última linha do bloco, no pedido para React.renderComponent() onde criamos o component <Simple/>. O objetivo de this.props é guardar a informação que foi passada para o componente. É considerada imutável e apenas um componente de nível mais superior pode fazer alterações e passé-la para a estrutura dos componentes.
  • Dentro de handleMouseDown também definimos um estado de utilizador com this.setState() para controlar o número de vezes que a mensagem foi mostrada. Vais reparar que usamos this.state no método render(). A qualquer momento que chames setState(), o React também acciona o método render() para manter o DOM em síncrono. Além do React.renderComponent()setState() é outra forma de forçar uma atualização visual.

Eventos Sintéticos

Os eventos expostos no DOM intermédio, como o onMouseDown, também actuam como uma camada de indirecção antes de serem definidos no DOM real. Estes eventos são assim referidos como Eventos Sintéticos. O React adota a delegação de eventos, uma técnica muito conhecida, e adiciona eventos apenas ao nível base do DOM real. Assim só existe um verdadeiro manipulador de eventos no DOM real. Adicionalmente, estes eventos sintéticos também fornecem um nível de consistência ao esconder as diferenças de browser e elementos.

A combinação do DOM intermédio e dos eventos sintéticos dá-te uma forma standard e consistente de definir IU entre diferentes browsers e até dispositivos.

Ciclo de vida do Componente

Os componentes na framework de React têm um ciclo de vida específico e materializam a máquina de estados que tem três estados distintos.

component-lifecyclecomponent-lifecyclecomponent-lifecycle

O Componente ganha vida depois de ser Executado. Executando resultados ao atravessar uma render-pass que gera o estrutura de componentes (DOM intermédio). Esta estrutura é convertida e colocada no nó contentor do DOM real. Isto é o resultado direto da invocação de React.renderComponent().

Assim que for definido, o componente fica no estado de Update. Um componente é atualizado quando mudas o estado através de setState() ou alteras as props usando setProps(). Isto, por sua vez, resulta em invocar render(), o que faz com que o DOM seja sincronizado com a informação (props + state). Entre as atualizações subsequentes, o React vai calcular o delta entre a estrutura anterior de componentes e a estrutura nova que foi gerada. Isto é um passo altamente otimizado (e uma característica de referência) que minimiza a manipulação do DOM real.

O estado final é Unmounted. Isto ocorre quando explicitamente chamas React.unmountAndReleaseReactRootNode() ou automaticamente se um componente foi um filho que não foi gerado na função render(). Na maior parte das vezes não tens que lidar com isto e apenas deixar que o React faça o mais apropriado.

Agora teria sido muito negligente, se o React não te dissesse quando mudou entre os estados Mounted-Update-Unmounted. Felizmente, este não é o caso e existem hooks que podes anular para ser notificado sobre as mudanças do ciclo de vida. Os nomes falam por si mesmos:

  • getInitialState(): prepara o estado inicial do Componente.
  • componentWillMount()
  • componentDidMount()
  • componentWillReceiveProps()
  • shouldComponentUpdate(): útil se quiseres controlar quando um render deve ser ignorado.
  • componentWillUpdate()
  • render()
  • componentDidUpdate()
  • componentWillUnmount()

Os métodos componentWill*  são chamados antes da mudança de estado e os métodos componentDid* são chamados depois.

Alguns nomes do métodos parecem ter recebido a sugestão das frameworks Cocoa no Mac e iOS

Características Diversas

Numa estrutura de componentes, a informação deve sempre fluir para baixo. Um componente pai deve definir as props de um componente filho para passar qualquer informação do pai para o filho. Isto é denominado o par Owner-Owned. Por outro lado, eventos de utilizador de mão (rato, teclado, toques) irão sempre subir do filho até ao componente origem.

data-event-flowdata-event-flowdata-event-flow

Quando crias o DOM intermédio no render(), podes também atribuir a propriedade ref para o componente filho. Depois podes referir-te a ele através do pai usando a propriedade refs. Isto está representado no código abaixo.

Como parte dos metadados do componente, podes definir o estado inicial ((getInitialState()), que vimos anteriormente nos métodos do ciclo de vida. Também podes definir os valores prédefinidos das props com getDefaultProps() e também estabelecer algumas regras de validação nestas props usando propTypes. O docs dão uma boa visão geral dos diferentes tipos de validação (controlos de escrita, requisitos, etc.) que podes executar.

O React também assegura o conceito de Mixin para extrair partes reutilizáveis de comportamento que podem ser injetadas nos Componentes distintos. Podes passar os mixins usando a propriedade mixins de um componente.

Agora, vamos à realidade e construir um Componente mais detalhado que usa estas funcionalidades.

Um Editor de Forma Construído Usando React

Neste exemplo, vamos construir um editor que aceita um DSL (Linguagem de Domínio Específico) simples para criar formas. Aos escreveres, verás o output correspondente ao lado, dando-te feedback em tempo real.

O DSL permite-te criar três tipos de formas: Elipse, Rectângulo e texto. Cada forma é especificada numa linha à parte juntamente com um conjunto de propriedade de estilo. A sintaxe é simples e utiliza um pouco de CSS. Para analisar uma linha, usamos um Regex que se pareçe com:

Como exemplo, o seguinte conjunto de linhas descreve dois rectângulos e uma label de texto...

...gerando o output mostrado abaixo:

react-shapes

Instalando

Muito bem, vamos em frente e construir este editor. Vamos começar com o ficheiro HTML (index.html), onde colocamos o markup de topo e incluímos as bibliotecas e os scripts da aplicação. Eu apenas estou a mostrar as partes relevantes aqui:

No código acima, a div contentor assegura o nosso DOM do React gerado. Os scripts da nossa aplicação estão incluídos no diretório /build. Estamos a usar JSX nos nossos componentes e o observador da linha de comandos (jsx), que coloca os ficheiros JS convertidos em /build. Nota que este comando de escuta é parte do módulo NPM react-tools.

O editor é dividido num conjunto de componentes, que estão listados abaixo:

  • ShapeEditor: o Componente raíz da estrutura de componentes
  • ShapeCanvas: responsável por gerar os Components das formas (Elipse, Rectângulo, Texto) Está contido no ShapeEditor.
  • ShapeParser: responsável por analisar texto e extrair a lista das definições de formas. Analisa linha por linha com o Regex que vimos anteriormente. Linhas inválidas são ignoradas. Isto não é realmente um componente, mas sim um objeto JS auxiliar, usado pelo ShapeEditor.
  • Elipse, Rectângulo, Texto: os Componentes das formas. Estes tornam-se filhos do ShapeCanvas.
  • ShapePropertyMixin: fornece funções auxiliares para extrair estilos encontrados nas definições das formas. Isto é combinado na estrutura de Componentes das formas usando a propriedade mixins.
  • app: o ponto de partida para o editor. Gera o componente raíz (ShapeEditor) e permite-te escolher um exemplo de forma a partir do drop-down.

A relação destas entidades é mostrada na anotada estrutura de componentes.

component-treecomponent-treecomponent-tree

O Componente ShapeEditor

Vamos olhar para a implementação de alguns destes componentes, começando com o ShapeEditor.

Como o nome sugere, o ShapeEditor fornece a experiência de edição ao gerar a <textarea/> e o feedback em tempo real na <ShapeCanvas/>. Ele escuta o evento onChange (eventos no React são sempre denominados com camel case) na <textarea/> e em cada alteração, define a propriedade texto do estado do componente. Como mencionado anteriormente, sempre que defines o estado usando setState(), o render é chamado automaticamente. Neste caso, o render() do ShapeEditor é chamado onde analisamos o texto do estado e reconstruímos as formas. Nota que estamos a começar com um estado inicial de texto vazio, que é definido no hook getInitialState().

Para separar o texto num conjunto de formas, usamos uma instância do ShapeParser. Deixei de lado os detalhes da análise sintática (parser) para manter a discussão focada no React. A instância do parser é criada no hook componentWillMount(). Este é chamado mesmo antes de definir o component e é um bom sítio para fazer qualquer inicialização antes de ocorrer o primeiro render.

É geralmente recomendado que passes todo o teu processamento complexo através do método render(). Os manipuladores de eventos só definem o estado enquanto o render() for o centro de toda a tua lógica.

O ShapeEditor usa esta ideia para fazer parsing dentro do seu render() e encaminha as formas detectadas ao definir a propriedade shapes do ShapeCanvas. É assim que a informação percorre a estrutura dos componentes, desde o proprietário (ShapeEditor) até à propriedade (ShapeCanvas).

Um último aspecto a ter em conta aqui é que nós temos na primeira linha um comentário que indica a tradução JSX -> JS.

ShapeCanvas para Gerar as Formas

A seguir, vamos seguir para o ShapeCanvas e para os componentes Elipse, Rectângulo e Texto.

O ShapeCanvas é bastante óbvio com a sua principal responsabilidade de gerar os componentes respetivos <Ellipse/>, <Rectangle/> e <Text/> através das definições de formas passadas (this.props.shapes). Para cada forma, passamos nas propriedades traduzidas com a expressão atributo: properties={shape.properties}.

Uma coisa diferente aqui é que a nossa estrutura de componentes não é estática, como temos no ShapeEditor. Em vez disso, é gerado dinamicamente por um loop sobre as formas que foram passadas. Também mostramos a mensagem "No shapes Found" se  não houver nada para mostrar.

As Formas: Elipse, Rectângulo, texto

Todas as formas têm uma estrutura semelhante e apenas diferem no estilo. Elas também usam o ShapePropertyMixin para lidar com a geração do estilo.

Aqui está a Elipse:

A implementação para extractStyle() é fornecida pelo ShapePropertyMixin.

O componente Rectângulo segue o processo, obviamente sem o estilo border-radius. O componente Texto tem uma propriedade extra chamada value que define o texto interior da <div/>.

Aqui está o Texto, para tornar isto claro:

Tentando Todos em conjunto com a App.js

app.js é onde colocamos todos em conjunto. Aqui nós renderizamos o componente raíz, o ShapeEditor e também fornecemos o apoio para alterar entre alguns exemplos de formas. Quando escolhes um exemplo diferente do dropdown, carregamos um texto pré-definido no ShapeEditor causando o update do ShapeCanvas. Isto ocorre no método readShapes().

Para exercitar o lado criativo, aqui está um robot construído usando o Shape Editor:

robot

E isto é o React para ti!

Phew! Isto foi um artigo extenso e ter atingido este ponto deve fazer sentir-te realizado!

Explorámos muitos conceitos aqui: o papel integral dos Componentes na framework, uso de JSX para descrever facilmente uma estrutura de componentes (aka DOM intermédio), vários hooks para integrar no ciclo de vida do componente, uso do state e props para conduzir o processo de renderização, uso de Mixins para factorizar comportamento reutilizável e finalmente juntar tudo no exemplo do Editor de Formas.

Espero que este artigo te dê estímulo suficiente para construir algumas aplicações React para ti. Para continuar a explorar, aqui estão alguns links úteis:

Seja o primeiro a saber sobre novas traduções–siga @tutsplus_pt no Twitter!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Scroll to top
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.