SuspenseList: orquestar el orden de revelado
Cuando varios Suspense hermanos resuelven a tiempos impredecibles, el contenido aparece en desorden y la página salta. SuspenseList impone un orden de revelado sobre esos límites —forwards de arriba abajo, backwards de abajo arriba, together todo a la vez— con independencia de quién termine primero, y tail controla cómo se muestran los fallback de lo que aún no toca aparecer: collapsed solo el siguiente, hidden ninguno, o todos por defecto. Ordena la aparición, no la carga: los recursos siguen cargando en paralelo. Se puede anidar para coordinar bloques dentro de bloques.
Qué coordina SuspenseList
SuspenseList no carga nada ni suspende por sí mismo: es un coordinador que observa a sus Suspense hijos directos (y a otros SuspenseList anidados) y decide en qué secuencia se les permite revelar su contenido. Los recursos de cada límite siguen disparándose en paralelo desde el primer momento; lo que SuspenseList intercepta es el instante de aparición, reteniendo a un límite ya resuelto si su turno todavía no llegó según el orden que pediste.
Sin un SuspenseList, tres Suspense hermanos revelan cada uno en cuanto su propio recurso resuelve, en el orden impredecible de la red:
// Sin coordinar: cada límite aparece cuando quiere; el orden lo decide el azar.<> <Suspense fallback={<Fila />}><Articulo id="a" /></Suspense> <Suspense fallback={<Fila />}><Articulo id="b" /></Suspense> <Suspense fallback={<Fila />}><Articulo id="c" /></Suspense></>;Envolverlos en un SuspenseList es todo lo que hace falta para imponerles una secuencia:
import { Suspense, SuspenseList } from "solid-js";<SuspenseList revealOrder="forwards" tail="collapsed"> <Suspense fallback={<Fila />}><Articulo id="a" /></Suspense> <Suspense fallback={<Fila />}><Articulo id="b" /></Suspense> <Suspense fallback={<Fila />}><Articulo id="c" /></Suspense></SuspenseList>;Aunque el artículo b termine su carga antes que a, con revealOrder="forwards" no se mostrará hasta que a haya aparecido. El usuario ve las filas llenarse en orden natural, de arriba abajo, como si cargaran secuencialmente, aunque por dentro corrieran todas a la vez. Ganas la lectura ordenada sin pagar la latencia de cargar en fila.
revealOrder: forwards, backwards, together
revealOrder admite tres valores. forwards revela en el orden del documento: cada límite espera a que el anterior aparezca, aunque él estuviera listo antes. backwards hace lo mismo en sentido inverso, de abajo arriba —útil para historiales o chats donde lo último ancla la vista—. together retiene a todos hasta que el último resuelve y entonces los revela de golpe, convirtiendo a muchos límites en un único momento de aparición coordinado.
revealOrder |
Orden de aparición | Uso típico |
|---|---|---|
forwards |
de arriba abajo, en orden de documento | feeds y listas |
backwards |
de abajo arriba | chats e historiales anclados |
together |
todos a la vez, al resolver el último | rejillas y unidades visuales |
La elección comunica intención. forwards es el orden de lectura por defecto de casi cualquier feed o lista occidental. together sirve cuando las piezas forman una unidad visual y verlas aparecer por separado rompería la composición —una rejilla de tarjetas que debe cuajar entera—. Y backwards es el idioma de las interfaces ancladas abajo. En los tres casos, el reparto de revelado es una decisión de diseño explícita, no el azar de qué petición ganó la carrera.
tail: cómo se muestran los pendientes
Ordenar el revelado deja una pregunta abierta: mientras esperas a que llegue el turno de cada límite, ¿cuántos fallback se ven? Eso lo gobierna tail. Por defecto —sin tail— se muestran todos los fallback de los límites que aún no han revelado, así que ves la lista completa de esqueletos desde el principio. Con tail="collapsed" se muestra solo el fallback del siguiente en aparecer, ocultando el resto. Con tail="hidden" no se muestra ningún fallback de los pendientes: el contenido simplemente crece a medida que se revela.
// Solo un indicador a la vez, el del próximo en aparecer.<SuspenseList revealOrder="forwards" tail="collapsed"> {items.map((it) => ( <Suspense fallback={<FilaEsqueleto />}> <Fila datos={it} /> </Suspense> ))}</SuspenseList>;tail |
Fallbacks visibles de lo pendiente |
|---|---|
| sin valor (por defecto) | todos los esqueletos a la vez |
collapsed |
solo el del siguiente en aparecer |
hidden |
ninguno |
collapsed es la opción idónea para listas largas o scroll infinito: en vez de renderizar cientos de esqueletos, muestras uno que anuncia la continuación. hidden encaja cuando ni siquiera quieres insinuar la espera. Y el modo por defecto —todos visibles— conviene a listas cortas de tamaño conocido, donde ver el molde completo desde el inicio evita el salto de layout. revealOrder decide la secuencia; tail decide el ruido de esa secuencia.
Anidar SuspenseList
Un SuspenseList puede contener a otro, y ahí está su verdadera potencia composicional: la lista externa trata a la interna como una sola unidad de revelado. Así coordinas la aparición de bloques enteros y, dentro de cada bloque, la de sus elementos, con políticas distintas en cada nivel.
<SuspenseList revealOrder="forwards"> <ProfileHeader /> <SuspenseList revealOrder="together"> <Suspense fallback={<Tarjeta />}><Foto /></Suspense> <Suspense fallback={<Tarjeta />}><Bio /></Suspense> </SuspenseList> <SuspenseList revealOrder="forwards" tail="collapsed"> {posts.map((p) => ( <Suspense fallback={<FilaEsqueleto />}><Post datos={p} /></Suspense> ))} </SuspenseList></SuspenseList>;La cabecera aparece primero; después el bloque foto-más-bio cuaja de golpe con su together; y por último el feed se revela fila a fila con un solo esqueleto a la vista. El árbol de listas te da un lenguaje jerárquico para orquestar toda la aparición de una página compleja, cada rama con su ritmo, sin que ninguna deje de cargar en paralelo por debajo.