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

Renderizado condicional

Un visitante que inició sesión ve un panel de control, uno que no inició sesión ve un formulario de login, y una solicitud fallida necesita mostrar un mensaje de error en algún lugar de la página. Un booleano como isLoggedIn generalmente vive en el estado, y lo que cambia es cuál pieza 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 justo en la declaración return.

Elegir entre dos elementos con un operador ternario

Cuando hay exactamente dos cosas que una pieza 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 />, de lo contrario se evalúa a <Login />. Lo que sea que se evalúe se renderiza en ese lugar del JSX. Las llaves son lo que te permite insertar una expresión JavaScript en el medio del marcado, y un ternario es una expresión como cualquier otra.

Mostrar u ocultar un elemento con &&

La segunda línea maneja un tipo diferente de decisión: mostrar algo, u no mostrar nada. hasError && <p>Algo salió mal</p> usa el operador && tal como funciona en cualquier otro lugar de JavaScript. Si hasError es false, && cortocircuita y toda la expresión se evalúa a false, sin llegar nunca 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 qué hace React con el resultado. React no renderiza nada para false, null e undefined, así que cuando hasError es false, nada aparece en la página.

La trampa de los valores falsos

&& no solo produce true o false. Como cualquier expresión JavaScript que usa &&, se evalúa a lo que sea que alcance, y ese lado puede ser cualquier valor, no necesariamente un booleano. La mayoría de las veces 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 e undefined, pero 0 es un valor real y renderizable, así que React lo pone en la página. El badge no aparece, pero un 0 suelto sí, justo donde esperabas que no hubiera nada.

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

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 badge o no renderiza nada, sin dejar un 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 devolver temprano:

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

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

Cuando message está vacío, la función devuelve null antes de construir el resto del JSX. Eso mantiene el return principal enfocado en el caso donde realmente hay 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. Dos elementos: usa un ternario. Un elemento o nada: usa &&. Un componente sin nada que renderizar: devuelve temprano con if (!x) return null antes del return principal, en lugar de envolver todo el árbol de JSX en una condición más. Mezclarlos, un ternario donde && sería suficiente o un early return enterrado dentro de un ternario, es generalmente una señal de que debes cambiar a la herramienta más directa.

La lección de la trampa de los falsos desde {count && <Badge />} no se limita a 0. NaN se renderiza de la misma manera, 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 suelto 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 Boolean(...), en lugar de confiar en que el valor bruto sea falso de la manera 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 inline:

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

Dos opciones para limpiar esto. Extrae la decisión a una variable encima del return, para que el JSX solo tenga que insertar 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 devuelva 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 deja que inserte valores que ya fueron decididos arriba.

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

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

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

Cuando isEditing cambia, EditForm y ViewForm son tipos de componentes diferentes ocupando la misma posición, así que React desmonta el anterior y monta el nuevo desde cero. Cualquier estado que EditForm estuviera manteniendo, un valor de entrada que el usuario estaba escribiendo, por ejemplo, desaparece en el momento en que ViewForm toma su lugar. Esto es diferente de renderizar el mismo tipo de componente con diferentes props en esa posición: 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 "lo mismo, actualizado" o "algo completamente nuevo".

JunoDecidir qué mostrar es JavaScript ordinario Un ternario elige entre dos elementos, && muestra un elemento o no muestra nada, y devolver null desde un componente es cómo dices "no hay nada que renderizar aquí". Ten 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 booleano verdadero.
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 que debes recordar con && es que se evalúa a lo que sea que alcance, así que un número falso como 0 se renderiza como tal en lugar de desaparecer. Protégete contra ello haciendo el lado izquierdo 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 Cada truco de renderizado condicional aquí es JavaScript ordinario evaluado dentro de JSX, y la única parte específica de React es que false, null e undefined se renderizan como nada mientras que cualquier otro valor, incluyendo 0, se renderiza como tal. Eso es lo que hace que {count && <Badge />} sea una trampa y {count > 0 && <Badge />} 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 desaparecerá, porque React ve un elemento nuevo, no una actualización del anterior.

A continuación: Formularios, donde usarás estado para manejar campos de entrada.