Aprenda React - Conhecendo JSX

September 06, 2018

No último post sobre React, criamos um projeto React utilizando Webpack, com algumas funcionalidades bacanas. Agora, vamos explorar um pouco o JSX, que é uma extensão de sintaxe para o Javascript e que é muito usada em aplicações em React.

Com o JSX, você pode escrever Javascript que se assemelha muito com HTML, facilitando bastante na hora de desenvolver o front-end de suas aplicações em React. Vamos então ver algumas das coisas que podemos fazer com JSX.

Vamos partir da estrutura que montamos no post anterior. Clique aqui para dar uma olhada, e pode encontrar o link para o repositório do Github que você pode clonar para seguir junto.

Funcionalidades básicas

Apenas para deixar registrado o nosso ponto de partida, neste momento temos este código React bem básico:

import React from "react";
import ReactDOM from "react-dom";

const Index = () => {
  return <div>Hello React!</div>;
};

ReactDOM.render(<Index />, document.getElementById("index"));

No código acima, ao retornar o elemento div dentro da função do Javascript, já estamos usando JSX.

A primeira coisa que veremos é que podemos incluir os valores de variáveis no elemento HTML que está sendo retornado. A forma mais básica é incluindo a variável dentro de chaves ({ }). Vejamos:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

const Index = () => {
  return <div>Hello { name }!</div>;
};

ReactDOM.render(<Index />, document.getElementById("index"));

Primeiro, definimos a variável name, e então a incluímos no elemento HTML. Ao acessar sua aplicação, poderá ver que o valor da variável está no div.

Podemos também fazer uma chamada a uma função pré-definida:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

function yellName(nameToYell) {
  return nameToYell.toUpperCase();
}

const Index = () => {
  return <div>Hello { yellName(name) }!</div>;
};

ReactDOM.render(<Index />, document.getElementById("index"));

Ao atualizar sua aplicação no navegador, repare que as letras da variável name agora estão todas maiúsculas.

Existem também limitações

Vamos agora ver também uma limitação do JSX. Tente adicionar um parágrafo logo após o div, deixando seu código da seguinte forma:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

function yellName(nameToYell) {
  return nameToYell.toUpperCase();
}

const Index = () => {
  return <div>Hello { yellName(name) }!</div> Here, a paragraph!;
};

ReactDOM.render(<Index />, document.getElementById("index"));

Bem, se você atualizar seu navegador, verá que nada será renderizado. Ao conferir o console do navegador ou o terminal onde está sendo executado o servidor do Webpack, você poderá ver a seguinte mensagem de erro: SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag.

A mensagem é bem clara. Quando você tem 2 elementos JSX, você precisa envolvê-los em uma única tag. A função que define o que será renderizado deve sempre retornar um único elemento mais externo. Dentro dele, podem haver tantos elementos quanto necessário, mas o mais externo deve ser único.

Até o React 16, a forma de resolver este problema era envolver os elementos em um div. Seu código ficaria assim:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

function yellName(nameToYell) {
  return nameToYell.toUpperCase();
}

const Index = () => {
  return (
    <div>
      <div>Hello { yellName(name) }!</div>
      Here, a paragraph!
    </div>
  );
};

ReactDOM.render(<Index />, document.getElementById("index"));

Agora, com o div envolvendo os 2 elementos, a aplicação é renderizada e os 2 elementos exibidos corretamente. Repare também que não há necessidade de ter o elemento todo em uma única linha. Você pode quebrar o elemento em várias linhas para facilitar a leitura e organização.

Com a chegada do React 16 (que é o que você deve estar usando, se seguiu o passo a passo do post sobre Webpack), é possível retornar uma lista de elementos. E aí, seu código ficará assim:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

function yellName(nameToYell) {
  return nameToYell.toUpperCase();
}

const Index = () => {
  return [
    <div>Hello { yellName(name) }!</div>,
    Here, a paragraph!
  ];
};

ReactDOM.render(<Index />, document.getElementById("index"));

Ao atualizar o seu navegador, sua aplicação continuará funcionando, da mesma forma. Em minha opinião, retornar a lista fica mais bacana, e você não precisa ficar criando elementos HTML que não estariam ali se não fosse para satisfazer a regra do React, mas use a forma que lhe agradar mais.

Estruturas de controle e repetição

Seguindo a linha do Javascript com HTML, é possível utilizar estruturas de controle e repetição. Renderização condicional, por exemplo, pode ser conseguida simplesmente utilizando um simples bloco if, aquele mesmo que você está acostumado a usar no Javascript padrão:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

function sayHello(name) {
  if (name) {
    return Hello { name }!;
  } else {
    return Hello, nobody;
  }
}

const Index = () => {
  return sayHello(name);
};

ReactDOM.render(<Index />, document.getElementById("index"));

Atualize seu navegador e verá, em sua aplicação, que o parágrafo renderizado é o primeiro, que inclui a variável que definimos. Agora, comente a linha onde definimos a variável name e atualize novamente seu navegador. O parágrafo que é renderizado agora é o segundo, com a mensagem Hello, nobody.

Outra forma comum de fazer a renderização de forma condicional é usando o operador ternário. Ele funciona da seguinte forma: { condicao ? renderiza isto se for verdadeiro : renderiza isto se for falso }. Vejamos com o mesmo exemplo anterior que usava um bloco if, mas agora reescrito para usar o operador ternário:

import React from "react";
import ReactDOM from "react-dom";
 
const name = "Felipe";
 
const Index = () => {
  return (
    <div>
      { name ? Hello { name }! : Hello, nobody }
    </div>
  )
};
 
ReactDOM.render(<Index />, document.getElementById("index"));

Essa forma é bem mais simples e limpa do que utilizar o if com dois blocos de template. Você pode fazer o mesmo teste que fizemos no exemplo anterior, comentando a variável e reparando em como o parágrafo renderizado é de fato aquele definido se a condição não é verdadeira.

Repare que você também pode apenas querer renderizar algo se dada condição é atendida, sem renderizar nada caso não seja, como um banner de erro, por exemplo. Para isso, usamos o bloco if normalmente, mas sem o else, ou então, no operador ternário, basta que retornemos null na última parte do mesmo. Veja o exemplo com o operador ternário:

import React from "react";
import ReactDOM from "react-dom";
 
const name = "Felipe";
 
const Index = () => {
  return (
    <div>
      { name ? Hello { name }! : null }
      How are you?
    </div>
  )
};

ReactDOM.render(<Index />, document.getElementById("index"));

Com o código acima, os 2 parágrafos serão exibidos. Entretanto, caso você comente a linha que define a variável name, você verá que o parágrafo com o Hello não é mostrado.

Para iterar sobre uma coleção, ao invés de um for, onde precisaríamos adicionar os itens a serem renderizados dentro de uma lista para retorná-la ao final, podemos usar o map, que já retorna a lista pronta para ser passado para o template. Veja como fica:

import React from "react";
import ReactDOM from "react-dom";

const names = ["Felipe", "Jose", "Alfredo"];

const Index = () => {
  return <div>
    {
      names.map((name, count) => {
        return <p key={ count }>Hello, { name }!
      })
    }
  </div>;
};

ReactDOM.render(<Index />, document.getElementById("index"));

Repare que agora, em nosso parágrafo, definimos um valor para a key. Este valor é necessário quando trabalhamos com conjuntos de elementos, para que o React possa fazer a renderização corretamente. Caso você não o defina, a aplicação até vai renderizar, mas você receberá um aviso.

Atributos de elementos

Mais um ponto importante a notar aqui são os atributos para elementos em JSX. O mais comum deles, o atributo class, usado para atribuir classes para elementos a serem estilizados com CSS, deve ser substituído por className. Outro atributo comum que também é diferente no JSX é o for, muito usado com labels para formulários. No JSX, você deve substituí-lo por htmlFor. Para um detalhamento completo de todas as diferenças entre atributos em elementos JSX, confira este link:

E este é um bom começo para entender o uso de JSX com React. No próximo post, falaremos de componentes e como melhor organizar suas aplicações.