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

Renderizado condicional

Un visitante conectado ve un panel de control, uno desconectado ve un formulario de inicio de sesión, y una solicitud fallida necesita que aparezca un mensaje de error en algún lugar de la página. Un booleano como isLoggedIn generalmente vive en estado, y lo que cambia es cuál fragmento de interfaz se renderiza según su valor actual. JSX es JavaScript, así que decidir qué renderizar funciona igual que cualquier otra decisión en tu código: una expresión que elige un valor, evaluada ahí mismo en la declaración return.

Elegir entre dos elementos con un operador ternario

Cuando hay exactamente dos cosas que un fragmento de interfaz podría ser, el operador ternario elige entre ellas:

jsx
return (
  <div>
    {isLoggedIn ? <Dashboard /> : <Login />}
    {hasError && <p>Algo salió mal</p>}
  </div>
)

isLoggedIn ? <Dashboard /> : <Login /> se lee igual que cualquier otro ternario: si isLoggedIn es verdadero, esta expresión se evalúa a <Dashboard />, si no, se evalúa a <Login />. Lo que sea que evalúe se renderiza en ese lugar del JSX. Las llaves son lo que te permite insertar una expresión JavaScript en medio del marcado, y un ternario es una expresión como cualquier otra.

Mostrar u ocultar un elemento con &&

La segunda línea maneja una forma diferente de decisión: mostrar algo, u no mostrar nada. hasError && <p>Algo salió mal</p> usa el operador && de la manera que funciona en todas partes en JavaScript. Si hasError es false, && cortocircuita y toda la expresión se evalúa a false, sin nunca llegar al JSX de la derecha. Si hasError es true, la expresión se evalúa al elemento <p>.

La razón por la que esto se renderiza correctamente depende de lo que React hace con el resultado. React no renderiza nada para false, null, y undefined, así que cuando hasError es false, nada aparece en la página en absoluto.

La trampa de los valores falsos

&& no solo produce true o false. Como cualquier expresión JavaScript que usa &&, se evalúa al lado en el que termina, y ese lado puede ser cualquier valor, no necesariamente un booleano. La mayoría del tiempo eso es inofensivo, pero se convierte en un error cuando el lado izquierdo es un número:

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

Si count es 0, esta expresión se evalúa a 0. React no renderiza nada para false, null, y undefined, pero 0 es un valor real y renderizable, así que React lo pone en la página. El distintivo no aparece, pero un 0 extraviado sí, justo donde esperabas nada.

La solución es asegurarte de que el lado izquierdo de && siempre sea un booleano real:

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

count > 0 siempre se evalúa a true o false, así que la expresión renderiza el distintivo o no renderiza nada, sin dejar ningún 0 atrás.

No renderizar nada en absoluto

A veces un componente no tiene nada que mostrar, y la forma más clara de decirlo es retornar temprano:

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

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

Cuando message está vacío, la función retorna null antes de construir el resto del JSX. Eso mantiene el return principal enfocado en el caso donde hay realmente algo que renderizar, en lugar de envolver todo en una condición más.

Qué herramienta usar depende de lo que la condición está eligiendo entre. Dos elementos: usa un ternario. Un elemento o nada: usa &&. Un componente sin nada que renderizar: retorna temprano con if (!x) return null antes del return principal, en lugar de envolver todo el árbol JSX en una condición más. Mezclarlos, un ternario donde && sería suficiente o un retorno temprano enterrado dentro de un ternario, generalmente es una señal de cambiar a la herramienta más directa.

La lección de la trampa falsa de {count && <Badge />} no se limita a 0. NaN se renderiza de la misma forma, así que {total / count && <Badge />} puede imprimir NaN en la página si count es 0. Una cadena vacía "" es la versión más silenciosa del mismo error: {name && <Greeting name={name} />} no renderiza nada visible cuando name es "", porque una cadena vacía en la página es invisible, pero sigue siendo un nodo de texto extraviado en el DOM. La solución es la misma que se usa para 0: fuerza el lado izquierdo a un booleano explícito, con una comparación como count > 0 o una llamada a Boolean(...), en lugar de confiar en que el valor bruto sea falso de la forma que esperas.

Las condiciones se vuelven más difíciles de leer una vez que hay más de una en juego. Un ternario anidado dentro de otro ternario en JSX es la primera señal de que una condición ha superado la lógica en línea:

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

Dos opciones para limpiar esto. Extrae la decisión a una variable por encima del return, así el JSX solo tiene que incrustar el resultado:

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

return <div>{view}</div>

O extrae la lógica a una pequeña función auxiliar que retorna el elemento correcto, que se lee mejor una vez que hay más de dos o tres ramas. De cualquier forma, el objetivo es el mismo: mantén el JSX mismo libre de decisiones y déjalo incrustar valores que ya fueron decididos arriba.

Retornar null de un componente no renderiza nada: ningún nodo del DOM se crea para él, ni siquiera uno vacío. Es un valor de retorno legítimo para un componente, y React trata un retorno null de la misma forma que trata un fragmento vacío.

Hay una segunda cosa que vale la pena conocer una vez que empiezas a intercambiar componentes dentro y fuera del mismo lugar. React reconcilia el árbol caminando por él posición por posición, y en cada posición compara el tipo de elemento que está ahí ahora contra el tipo que estaba en el render anterior.

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

Cuando isEditing cambia, EditForm y ViewForm son tipos de componente diferentes ocupando la misma posición, así que React desmonta el antiguo y monta el nuevo desde cero. Cualquier estado que EditForm estuviera manteniendo, un valor de entrada que el usuario estuviera escribiendo, por ejemplo, desaparece en el momento en que ViewForm toma su lugar. Esto es diferente a renderizar el mismo tipo de componente con diferentes props en esa posición: el mismo tipo en la misma posición significa que React actualiza la instancia existente y su estado sobrevive. El tipo es lo que determina si React ve "la misma cosa, actualizada" o "una cosa completamente nueva".

JunoDecidir qué mostrar es JavaScript ordinario Un ternario elige entre dos elementos, && muestra un elemento o nada, y retornar null de un componente es cómo dices "no hay nada que renderizar aquí".

Cuidado con {count && <Badge />} cuando count puede ser 0, ya que 0 es un valor que React realmente imprimirá. Escribir {count > 0 && <Badge />} en su lugar mantiene el lado izquierdo como un verdadero booleano.

JunoDecidir qué mostrar es JavaScript ordinario Usa un ternario cuando estés eligiendo entre dos elementos, y && cuando estés eligiendo entre un elemento y nada.

La trampa a recordar con && es que se evalúa al lado en el que termina, así que un número falso como 0 se renderiza como sí mismo en lugar de desaparecer. Protégete contra ello haciendo que el lado izquierdo sea un booleano explícito, como count > 0, y usa un return null temprano cuando un componente no tiene nada que mostrar.

JunoDecidir qué mostrar es JavaScript ordinario Todo truco de renderizado condicional aquí es JavaScript ordinario evaluado dentro de JSX, y la única parte específica de React es que false, null, y undefined se renderizen como nada mientras cada otro valor, incluyendo 0, se renderiza como sí mismo. Eso es lo que hace que {count && <Badge />} sea una trampa y {count > 0 && <Badge />} sea la solución.

La parte que vale la pena llevar adelante es la reconciliación por posición y tipo: intercambia un tipo de componente diferente en el mismo lugar y su estado desaparece, porque React ve un elemento nuevo, no una actualización del antiguo.

Lo siguiente: Formularios, donde usarás estado para manejar campos de entrada.