Afinal de contas, usar ? ou && na renderização condicional em React?

Me tornei um programador frontend profissional a quase 1 ano já e comecei a ter uma visão um pouco mais crítica acerca de práticas de sintaxe e clean code em projetos React.

Em minhas sessões diárias de estudos, percebi uma briga velada entre desenvolvedores que compartilham suas opiniões na internet: "Não use &&" ou "Não use operador ternário".

Em meu primeiro post sobre tecnologia na internet (e também no Tabnews), eu decidi dar a minha opinião sobre isso.

A utilização e conhecimento acerca da renderização condicional é indispensável no meio de um projeto React, nesse momento o desenvolvedor deve escolher qual estrutura lógica ele irá utilizar para tal fim. Quando me deparo com essa necessidade, eu me pergunto: "Irei renderizar apenas uma possibilidade?" Se a resposta for sim, eu opto pelo "(condição verdadeira) &&" (o famoso "então"), para facilitar a legibilidade do código. Em contrapartida, caso o elemento a ser renderizado tenha que aguardar o carregamento de dados (uma requisição em uma API ou o resolve de uma promise) e com isso mostrar um spinner de carregamento, eu opto pelo operador ternário ((condição)? se true : se false).

Isso pode até parecer óbvio, mas vejo que algumas pessoas preferem escrever operadores ternários e colocarem "null" ou um fragmento vazio (<></>) no bloco de código da condicional falsa, o que na minha visão tende a ser pouco (ou menos legível) do que o &&. Mas também não faz sentido utilizar dois blocos de código, o primeiro (condicional) && e o outro (!condicional) &&.

Por fim, minha conclusão é as linguagens e suas sintaxes são apenas ferramentas, algumas servindo muito bem para um propósito, e outras nem tanto. Não se prive de utilizar todo o potencial de uma ferramenta por mero desconhecimento das finalidades da mesma. Utilize ternário ou condicional &&, desde que o contexto da utilização faça sentido, sua aplicação será performática e clean.

Eu acho o && bem legível, mas como já foi falado aqui nos comentários, se for utilizar, precisa garantir que a comparação do lado esquerdo realmente seja à prova de erros. Eu sou mais do time ternário, acho que se o código está bem estruturado e identado, é tão legível quanto o &&.

Agora, fora a legibilidade de código, um ponto a se considerar é como o && trata alguns tipos de condições:

Exemplo 1:

function Cart({items}) {
  return (
    <div>
      <ul>
        {items.length &&
          items.map(item => (
            <li key={item.id}>
              {`Item: ${item.name} - R$ ${item.price}`}
            </li>
          ))}
      </ul>
    </div>
  )
}

Aqui se items é uma array vazia, o length é 0 e portanto apenas um 0 seria renderizado. A forma ideal de se livrar disso é com o ternário!

function Cart({items}) {
  return (
    <div>
      <ul>
        {items.length
          ? items.map(item => (
              <li key={item.id}>
                {`Item: ${item.name} - R$ ${item.price}`}
              </li>
            ))
          : null}
      </ul>
    </div>
  )
}

Aqui, se items for uma array vazia, o length é 0, que por sua vez é um valor falsy. Isso nos leva para a condição false do ternário que é null. Na tela nada é renderizado e assim se evita esse tipo de erro. Ou ainda poderia ter algo realmente personalizado do tipo:

function Cart({items}) {
  return (
    <div>
      <ul>
        {items.length
          ? items.map(item => (
              <li key={item.id}>
                {`Item: ${item.name} - R$ ${item.price}`}
              </li>
            ))
          : <p>Seu carrinho de compras está vazio!</p>}
      </ul>
    </div>
  )
}

Exemplo 2

function ErrorHandler({error}) {
  return error && <p>{error.message}</p>
}

Neste exemplo, podemos imaginar o caso de error ser undefined. Isso geraria uma mensagem de erro no console do tipo:

Uncaught Error: ErrorHandler(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.


Enfim, não é uma regra optar pelo ternário, mas acredito que é uma boa prática de escrita de código!

Muito bom os exemplos! Ao usar o `&&`, também podemos evitar problemas usando o `Boolean` ou o `!!`. Seguindo os exemplos: ```jsx function Cart({ items }) { return (
    {Boolean(items.length) && items.map((item) => (
  • {`Item: ${item.name} - R$ ${item.price}`}
  • ))}
); } ``` Ou: ```jsx function ErrorHandler({ error }) { return !!error &&

{error.message}

; } ```

Ao usar &&, temos que ter cuidado quando o lado esquerdo é um número, porque se for um 0, ele será renderizado. Um exemplo grosseiro:

const count = 0

//...

<div>
    {count && <p>The count is {count}</p>}
</div>

Teríamos o 0 renderizado:

<div>0</div>

É bom garantir que o lado esquerdo é sempre um booleano:

const count = 0

//...

<div>
    {count > 0 && <p>The count is {count}</p>}
</div>

Teríamos uma div vazia:

<div></div>
Obrigado pelo comentário.

Achei estranha essa ideia de usar um fragmento vazio em vez de um simples null. A única razão que eu vejo pra isso é se essa condicional está sendo passada numa função que espera um elemento necessariamente. Mas aí, se for o caso, provavelmente o código tá organizado de uma maneira bem esquisita.

Pessoalmente, eu não lembro de ter usado alguma vez a ideia do && que você mencionou, exceto quando acompanhando algum tutorial ou curso, mas não acho uma opção ruim. Pra mim, isso e o operador ternário são equivalentes em termos de legibilidade (exceto se a operação ternária ficar longa demais e não couber numa linha só). Usaria qualquer um dos dois tranquilamente dependendo do caso.

Muita gente na internet tem muitos "hot takes" sobre programação que podem parecer muito inteligentes quando a gente lê o artigo, mas nem sempre estão certos. Às vezes eles tomam um caso específico e bem raro como exemplo de por que tal jeito de fazer as coisas é terrível e deveria ser evitado.

Obrigado pelo comentário.