Os Pilares do React
18 de agosto, 2020 — 5 min read
O que é o React?
React é uma biblioteca do Javascript desenvolvida pelo Facebook para criação de interfaces baseadas em componentes, criada por Jordan Walke.
O React segue uma maneira declarativa de programar, encapsulando as lógicas em componentes específicos para cada parte da aplicação.
O foco deste post é introduzir os pilares necessários para desenvolver suas primeira aplicações com esse framework. Entendendo o conceito e como utilizar esses pilares já é possível utilizar grande parte dos recursos do React.
Introdução ao JSX
Considere esse o primeiro componente da aplicação:
import React from 'react'
function App() {
return (
<div className="App">
<h1>Hello ReactJS</h1>
</div>
)
}
export default App
Essa declaração estranha de tags não é uma string, muito menos HTML comum.
No início pode parece estranho, por que juntar HTML com o código JavaScript? Logo veremos que essa forma faz sentido e facilita na hora de desenvolver dentro do React, pois a lógica fica encapsulada no próprio componente.
JSX é uma extensão de sintaxe para o Javascript (JavaScript eXtension) baseado em XML(sintaxe do HTML). Lembrando que o navegador não entende essa sintaxe então deve ser transpilado utilizando por exemplo o Babel, que transforma o JSX em código Javascript.
O código transpilado para criar uma div vazia seria algo do tipo:
React.createElement('div', null)
Componentes
Quando trabalhamos com React utilizamos o conceito de componentização, ou seja, dividimos a UI em partes independentes, reutilizáveis e permitindo pensar em cada parte isoladamente.
Antigamente utilizávamos componentes de classe para trabalhar com estados mas hoje utilizamos somente componentes funcionais graças a “nova” API de hooks.
import React from 'react'
export default function Person() {
return <h1>O nome da pessoa é: André Zagatti</h1>
}
Essa função é um componente de React válido porque não está recebendo nenhum parâmetro(pode receber as propriedades como já vamos ver) e retorna um elemento JSX do React. Esses componentes são chamados de componentes funcionais, pois são literalmente funções do Javascript. Um detalhe, sempre que utilizarmos a sintaxe de JSX devemos importar o React.
import React from 'react'
import Person from './components/Person'
function App() {
return <Person />
}
export default App
Como vimos antes o React entende as tags do HTML no JSX mas também podemos utilizar nossos próprios componentes como tags.
Propriedades (props)
As props dos componentes do React se assemelham a atributos passados para tags do HTML.
import React from 'react'
export default function Person(props) {
return <h1>O nome da pessoa é: {props.name}</h1>
}
Agora o componente Person não fica preso a um nome estático e pode ser reutilizado simplesmente passando outro nome para as props.
import React from 'react'
import Person from './components/Person'
function App() {
return (
<div>
<Person name="Solaire of Astora" />
<Person name="Andre of Astora" />
<Person name="Sigmeyer of Catarina" />
</div>
)
}
export default App
Quando passamos dados utilizando as props de um componente temos que passar exatamente o nome que será usado dentro do componente como o nome da prop. Essa passagem de dados nomeados é normalmente chamada de Named/Labeled Arguments, com os objetos do JavaScript é muito fácil utilizar esse modelo.
Estado
O estado do componente é uma variável que armazena informações atuais do componente, caso haja uma alteração o componente e seus componentes filhos serão renderizados novamente(acontece o mesmo com as props).
Para utilizarmos o estado em componentes funcionais utilizamos a “nova” API do React chamada de hooks. O hook de estado se chama useState
, que é uma função que recebe o estado inicial e retorna um array sendo a primeira posição o valor do estado e a segunda uma função para atualizar esse valor seguindo os conceitos da imutabilidade.
import React, { useState } from 'react'
import Person from './components/Person'
function App() {
const [name, setName] = useState('')
/**
* É o mesmo que
* const nameState = useState('');
* const name = nameState[0];
* const setName = nameState[1];
*/
return (
<div>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<Person name={name} />
</div>
)
}
export default App
Nesse componente estamos utilizando os pilares do estado e de props.
Detalhando melhor o que o componente está fazendo, o [name, setName]
é uma desestruturação de array disponível no Javascript desde o ES6 onde o name
referencia o primeiro elemento do array e o setName
o segundo.
No input a propriedade value
é necessária para o valor exibido em tela do input refletir com o valor do state name
. Sobre o onChange
é um evento do input que disparada a cada nova letra digitada nele, o que é passado é o evento de mudança, então para pegarmos o valor digitado e inserir no state de name utilizando e.target.value
.
No componente de Person
podemos ver que não está sendo mais passada uma string e sim uma variável do Javascript, então para inserir Javascript dentro do JSX utilizamos as chaves. É interessante de se notar que podemos compartilhar o estado de um elemento pai para um elemento filho, que é uma coisa muito utilizada. Podemos também compartilhar o estado de um elemento filho para o pai mas é algo mais complexo e nem sempre necessário.
Hook de Efeito (useEffect)
Quando utilizávamos componentes de classe era comum utilizarmos os métodos de ciclo de vida do componente. Esses métodos ficavam responsáveis por executar funções e alterar dados quando o componente montava, era alterado ou era desmontado. Hoje com a API de hooks utilizamos um único hook para tratar esses casos, chamado de useEffect.
import React, { useState, useEffect } from 'react'
function App() {
const [count, setCount] = useState(0)
useEffect(() => {
const interval = setInterval(() => setCount(count + 1), 1000)
return () => {
clearInterval(interval)
}
}, [count])
return (
<div>
<h1>{count} segundos</h1>
</div>
)
}
export default App
O useEffect
recebe como primeiro parâmetro uma função de callback com o código que será executado quando o componente for montado, o segundo parâmetro é o array de dependências do hook de efeito, esse array de dependências são as variáveis externas utilizadas dentro dele e que ele observará, quando acontecer uma alteração nessas variáveis ele executará novamente.
Como tem uma alteração no state do componente todo segundo por conta do setInterval
é necessário passar uma callback de retorno do useEffect
para que ele consiga limpar o Interval quando o componente for desmontado, se essa callback de retorno não for passada acontecerá efeitos colaterais na aplicação de vários Interval’s estarão rodando ao mesmo tempo causando vazamento de memória e alterando o state repetidas vezes.
Existe uma sintaxe alternativa de utilização da função de alterar o estado que pode eliminar essa repetida execução do useEffect
(que causa muitos loops) retirando o count do array de dependências.
import React, { useState, useEffect } from 'react'
function App() {
const [count, setCount] = useState(0)
useEffect(() => {
setInterval(() => setCount((state) => state + 1), 1000)
}, [])
return (
<div>
<h1>{count} segundos</h1>
</div>
)
}
export default App
Utilizando um callback para alterar o estado é possível recuperar o valor atual do estado e utilizando ele já para criar um novo. Mas como funções como Interval podem ficar rodando em background sem que percebamos recomendo deixar o return limpando o Interval como precaução.
Bônus
Como bônus resolvi colocar como fazer uma chamada a API. Para isso usaremos o hook de efeito e a API nativa para requests HTTP chamada fetch.
import React, { useEffect } from 'react'
export default function App() {
useEffect(() => {
;(async () => {
const response = await fetch('https://api.github.com/users/azagatti')
const data = await response.json()
console.log(data)
})()
}, [])
return (
<div>
<h2>Fetch data!</h2>
</div>
)
}
Algumas coisas interessantes de se notar, não é possível usar diretamente o async
no useEffect
, então normalmente seria possível usar a sintaxe de Promise com then
mas podemos utilizar uma IIFE (Immediately invoked function expression) para escrever com a sintaxe de async
e await
.
O que fazer em seguida? Normalmente armazenaríamos esse data retornado da API num estado e realizaríamos um map no JSX
para mostrar os dados que quisermos, até poderíamos criar novos componente que recebam por props
esses dados e fiquem com a responsabilidade de exibir os valores.
Conclusão
Nesse post abordei o que considero os pilares para o desenvolvimento utilizando o React, entendendo como aplicar cada um deles já é possível desenvolver utilizando esse framework, mas isso é só o começo, existem mais conceitos, outros hooks e várias bibliotecas utilizadas no ecossistema do React que valem ser estudadas. Como por exemplo biblioteca para criação de rotas na página, trabalhar com formulários, referências dos elementos e muito mais.
Para quem quiser testar os códigos facilmente sem criar todo o ambiente, pode utilizar o código mostrado no post no Codesandbox, só comentar e tirar os comentários do que quiser: https://codesandbox.io/s/pensive-cache-cwohe