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!
-
{Boolean(items.length) &&
items.map((item) => (
- {`Item: ${item.name} - R$ ${item.price}`} ))}
{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>
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.