Skip to content
This page has been auto-translated and may contain errors.View in English

Renderização condicional

Um visitante logado vê um painel de controle, um visitante não logado vê um formulário de login, e uma requisição que falhou precisa mostrar uma mensagem de erro em algum lugar da página. Um booleano como isLoggedIn normalmente fica em state, e o que muda é qual pedaço de UI é renderizado de acordo com seu valor atual. JSX é JavaScript, então decidir o que renderizar funciona da mesma forma que qualquer outra decisão no seu código: uma expressão que escolhe um valor, avaliada ali mesmo dentro da instrução return.

Escolhendo entre dois elementos com ternário

Quando existem exatamente duas coisas que um pedaço de UI poderia ser, o operador ternário escolhe entre elas:

jsx
return (
  <div>
    {isLoggedIn ? <Dashboard /> : <Login />}
    {hasError && <p>Algo deu errado</p>}
  </div>
)

isLoggedIn ? <Dashboard /> : <Login /> se lê como qualquer outro ternário: se isLoggedIn é verdadeiro, essa expressão avalia para <Dashboard />, caso contrário avalia para <Login />. Seja qual for o resultado avaliado, ele é renderizado naquele local do JSX. As chaves são o que permite você colocar uma expressão JavaScript no meio da marcação, e um ternário é uma expressão como qualquer outra.

Mostrando ou ocultando um elemento com &&

A segunda linha lida com um tipo diferente de decisão: mostrar algo, ou mostrar nada. hasError && <p>Algo deu errado</p> usa o operador && do jeito que ele funciona em qualquer outro lugar do JavaScript. Se hasError é false, && avalia rapidamente e toda a expressão avalia para false, sem nunca chegar ao JSX à direita. Se hasError é true, a expressão avalia para o elemento <p>.

O motivo pelo qual isso é renderizado corretamente tem a ver com o que React faz com o resultado. React pula renderizar qualquer coisa para false, null e undefined, então quando hasError é false, nada aparece na página.

A pegadinha dos valores falsy

&& não produz apenas true ou false. Como qualquer expressão JavaScript usando &&, ela avalia para o lado em que termina, e esse lado pode ser qualquer valor, não necessariamente um booleano. Na maioria das vezes isso é inofensivo, mas vira um bug quando o lado esquerdo é um número:

jsx
{count && <Badge />}
// count = 0 → renderiza "0" na página

Se count é 0, essa expressão avalia para 0. React pula renderizar para false, null e undefined, mas 0 é um valor real e renderizável, então React coloca na página. O badge não aparece, mas um 0 solto aparece, bem onde você esperava nada.

A solução é garantir que o lado esquerdo de && sempre seja um booleano de verdade:

jsx
{count > 0 && <Badge />}
// count = 0 → renderiza nada

count > 0 sempre avalia para true ou false, então a expressão renderiza o badge ou renderiza nada, sem nenhum 0 deixado para trás.

Não renderizar nada

Às vezes um componente não tem nada para mostrar, e a forma mais clara de dizer isso é retornar cedo:

jsx
function Banner({ message }) {
  if (!message) {
    return null
  }

  return <p className="banner">{message}</p>
}

Quando message está vazio, a função retorna null antes de construir o resto do JSX. Isso mantém o return principal focado no caso onde realmente há algo para renderizar, em vez de envolver tudo em uma condição a mais.

Qual ferramenta usar depende do que a condição está escolhendo entre. Dois elementos: use ternário. Um elemento ou nada: use &&. Um componente que não tem nada para renderizar: retorne cedo com if (!x) return null antes do return principal, em vez de envolver toda a árvore de JSX em mais uma condição. Misturá-los, um ternário onde && seria melhor ou um retorno cedo escondido dentro de um ternário, é geralmente um sinal de trocar para a ferramenta mais direta.

A lição da pegadinha falsy em {count && <Badge />} não se limita a 0. NaN renderiza do mesmo jeito, então {total / count && <Badge />} pode imprimir NaN na página se count é 0. Uma string vazia "" é a versão mais silenciosa do mesmo bug: {name && <Greeting name={name} />} renderiza nada visível quando name é "", porque uma string vazia na página é invisível, mas ainda é um nó de texto solto sentado no DOM. A solução é a mesma usada para 0: force o lado esquerdo para um booleano explícito, com uma comparação como count > 0 ou uma chamada Boolean(...), em vez de confiar no valor bruto ser falsy da forma que você espera.

Condições ficam mais difíceis de ler uma vez que mais de uma está em jogo. Um ternário aninhado dentro de outro ternário em JSX é o primeiro sinal de que uma condição cresceu além da lógica inline:

jsx
{status === 'loading' ? <Spinner /> : status === 'error' ? <ErrorMessage /> : <Content />}

Duas opções para limpar isso. Puxe a decisão para uma variável acima do return, então o JSX só precisa embutir o resultado:

jsx
const view =
  status === 'loading' ? <Spinner /> :
  status === 'error' ? <ErrorMessage /> :
  <Content />

return <div>{view}</div>

Ou extraia a lógica para uma pequena função auxiliar que retorna o elemento correto, que se lê melhor uma vez que há mais de dois ou três ramos. De qualquer forma, o objetivo é o mesmo: mantenha o JSX em si livre de decisões e deixe ele embutir valores que já foram decididos acima.

Retornar null de um componente renderiza nada: nenhum nó DOM é criado para ele, nem mesmo um vazio. É um valor legítimo de retorno para um componente, e React trata um retorno null do mesmo jeito que trata um fragment vazio.

Há uma segunda coisa que vale a pena saber uma vez que você começa a trocar componentes dentro e fora do mesmo local. React reconcilia a árvore caminhando por ela posição a posição, e em cada posição compara o tipo de elemento que está lá agora contra o tipo que estava lá na última renderização.

jsx
{isEditing ? <EditForm /> : <ViewForm />}

Quando isEditing muda, EditForm e ViewForm são tipos de componentes diferentes ocupando a mesma posição, então React desmonta o antigo e monta o novo do zero. Qualquer state que EditForm estava mantendo, um valor de input que o usuário estava digitando, por exemplo, desaparece no momento em que ViewForm toma seu lugar. Isso é diferente de renderizar o mesmo tipo de componente com props diferentes naquele local: mesmo tipo na mesma posição significa que React atualiza a instância existente e seu state sobrevive. O tipo é o que determina se React vê "a mesma coisa, atualizada" ou "uma coisa nova inteiramente."

JunoDecidir o que mostrar é JavaScript ordinário Um ternário escolhe entre dois elementos, && mostra um elemento ou mostra nada, e retornar null de um componente é como você diz "não há nada para renderizar aqui." Fique atento a {count && <Badge />} quando count pode ser 0, já que 0 é um valor que React vai realmente imprimir. Escrever {count > 0 && <Badge />} em vez disso mantém o lado esquerdo um verdadeiro booleano.
JunoDecidir o que mostrar é JavaScript ordinário Use um ternário quando você está escolhendo entre dois elementos, e && quando você está escolhendo entre um elemento e nada. A pegadinha a lembrar com && é que ela avalia para o lado em que termina, então um número falsy como 0 é renderizado como a si mesmo em vez de desaparecer. Proteja-se contra isso tornando o lado esquerdo um booleano explícito, como count > 0, e use um return null cedo quando um componente não tem nada para mostrar.
JunoDecidir o que mostrar é JavaScript ordinário Cada truque de renderização condicional aqui é JavaScript ordinário avaliado dentro de JSX, e a única parte específica do React é que false, null e undefined renderizam como nada enquanto todo outro valor, incluindo 0, renderiza como a si mesmo. É isso que torna {count && <Badge />} uma armadilha e {count > 0 && <Badge />} a solução. A parte que vale a pena levar adiante é reconciliação por posição e tipo: coloque um tipo de componente diferente no mesmo local e seu state desaparece, porque React vê um elemento novo, não uma atualização do antigo.

Próximo: Formulários, onde você vai usar state para lidar com campos de entrada.