Carga y rendimiento
Carga y contenido diferido: distingue procesar una accion, pintar la UI por primera vez, aplazar bloques pesados y contener errores de render.
Cuatro situaciones que se confunden, cuatro componentes. Hay una accion en marcha y quieres avisar de que algo se esta procesando: DnzLoader. La interfaz todavia no esta lista y quieres mostrar el hueco que va a ocupar: DnzSkeleton. Tienes una subpagina o seccion cara de pintar y quieres aplazar su render hasta que toque: DnzDeferredContent. Y si un bloque puede petar al renderizar, lo aislas para que no se lleve la pagina entera: DnzTryComponent. Elige por el momento, no por el aspecto.
Cual va en cada caso
La confusion habitual es entre "estoy procesando una accion" y "la interfaz aun no esta lista". No son lo mismo:
| Necesitas | Usa | Por que |
|---|---|---|
| Avisar de que estas procesando: una seccion entera carga datos y aun no tienes nada que pintar | DnzLoader | Spinner neutro centrado en el hueco mientras esperas a OnInitializedAsync |
| Avisar de que la UI aun no esta lista: reservar el hueco con la forma del contenido (lista, tarjeta, KPIs) | DnzSkeleton | Esqueleto animado: el usuario ya ve cuanto va a ocupar, asi la espera se siente mas corta |
| Aplazar el render de un bloque pesado para que la pagina respire | DnzDeferredContent | Pinta primero un skeleton y monta el contenido real tras un delay; ideal para revelado progresivo |
| Que un componente que puede fallar no tumbe toda la pagina | DnzTryComponent | Captura la excepcion de render y muestra un fallback en su lugar |
| Feedback de una accion concreta del usuario (un boton, 1-10s) | IsBusy=@variable en el boton | No es de esta familia: el spinner vive en el propio boton |
La regla rapida: DnzLoader = "estoy trabajando" (hay una operacion en curso). DnzSkeleton = "esto aun no esta" (la interfaz se esta montando). Si dudas, preguntate si hay datos viajando ahora mismo (loader) o si solo estas pintando el hueco a la espera (skeleton).
DnzLoader
Spinner neutro para cuando una seccion entera esta cargando datos y aun no tienes nada que pintar. Es el patron de "cargar en OnInitializedAsync y devolver pronto".
@if (Facturas.IsNull())
{
<DnzLoader />
}
else
{
<FacturasGridU Data=@Facturas />
}
@code {
private List<FacturaDTO> Facturas { get; set; }
protected override async Task OnInitializedAsync()
{
Facturas = await FacturasService.GetPendientesAsync();
}
}En barras o cabeceras estrechas, donde un spinner centrado no encaja, pasa Horizontal="true" para la variante compacta de puntos:
<div class="d-flex align-items-center gap-2">
<span>Sincronizando</span>
<DnzLoader Horizontal="true" />
</div>Parametros
| Parametro | Tipo | Por defecto | Que hace |
|---|---|---|---|
Horizontal | bool | false | false pinta el loader vertical centrado en el hueco; true usa la variante horizontal compacta (tira de puntos), util en barras o cabeceras estrechas |
DnzSkeleton
Reserva el hueco con rectangulos animados que imitan la forma del contenido que va a llegar. A diferencia del loader, el usuario ve cuantas lineas y que tamano va a ocupar, asi que la espera se siente mas corta.
@if (Movimientos.IsNull())
{
<DnzSkeleton Lines="5" Height="0.9rem" />
}
else
{
<MovimientosListaU Data=@Movimientos />
}Combina varios skeletons de distinto tamano para imitar un encabezado mas filas:
<DnzSkeleton Lines="1" Height="0.7rem" MaxWidth="55%" />
<DnzSkeleton Lines="2" Height="0.9rem" MaxWidth="100%" />Parametros
| Parametro | Tipo | Por defecto | Que hace |
|---|---|---|---|
Lines | int | 1 | Numero de rectangulos (lineas) que pinta. Ajustalo a las filas que esperas: una tarjeta 1, una lista 5, un formulario largo 20 |
Height | string | "1rem" | Alto de cada linea. Sube a "80px" para simular una tarjeta o KPI |
Radius | string | "0.25rem" | Radio de las esquinas de cada rectangulo |
MaxWidth | string | "100%" | Ancho maximo del bloque. Limitalo ("400px", "55%") cuando el skeleton no deba ocupar todo el ancho |
DnzDeferredContent
Envuelve un bloque pesado y aplaza su montaje: durante el delay pinta un esqueleto y, pasado ese tiempo, monta el contenido real. Es la pieza clave para que paginas con muchas subvistas aparezcan rapido en lugar de bloquearse pintando todo de golpe.
<DnzDeferredContent DelayMs="300">
<VentasPorMesGraficoU Data=@Resumen />
</DnzDeferredContent>Por que importa para el rendimiento. En una pagina con muchas subvistas (un dashboard, una ficha con varias pestanas, un listado con tarjetas pesadas), Blazor intenta renderizar todo en el primer paso. Envolviendo cada bloque caro en un DnzDeferredContent con delays crecientes, lo importante sale ya y el resto llega escalonado: la pagina da sensacion de velocidad aunque el trabajo total sea el mismo.
Patron de revelado progresivo en un dashboard: los KPIs (lo importante) salen ya, las tarjetas pesadas llegan escalonadas.
<DnzDeferredContent DelayMs="0">
<KpiSeccionU Data=@Kpis />
</DnzDeferredContent>
<DnzDeferredContent DelayMs="300">
<RadzenCard>
<VentasPorMesGraficoU Data=@Ventas />
</RadzenCard>
</DnzDeferredContent>
<DnzDeferredContent DelayMs="600">
<RadzenCard>
<TopClientesTablaU Data=@TopClientes />
</RadzenCard>
</DnzDeferredContent>Si no te vale el skeleton por defecto, pasa tu propio indicador de carga en LoadingContent:
<DnzDeferredContent DelayMs="800" Class="p-3">
<LineasFacturaU Data=@Lineas />
<LoadingContent>
<DnzLoader />
</LoadingContent>
</DnzDeferredContent>Parametros
| Parametro | Tipo | Por defecto | Que hace |
|---|---|---|---|
DelayMs | int | 500 | Milisegundos antes de montar el contenido real. 0 pinta ya; usa valores crecientes (300, 600...) para escalonar secciones |
ChildContent | RenderFragment | El contenido pesado que se aplaza. Es lo que pones entre las etiquetas del componente | |
LoadingContent | RenderFragment | Indicador de carga a medida mientras espera. Si no lo pasas, usa un DnzSkeleton | |
Class | string | "" | Clase CSS para el contenedor del estado de carga (p. ej. "p-3" para darle aire) |
DnzDeferredContent aplaza el render, no la carga de datos. Si lo caro es la query, traela en OnInitializedAsync y combina con DnzLoader/DnzSkeleton. El diferido solo reparte el coste de pintar la interfaz, no el de ir a buscar los datos.
DnzTryComponent
Envuelve un bloque que puede petar al renderizar y captura la excepcion para que no se lleve la pagina entera. Es un ErrorBoundary con un fallback opcional a medida.
<DnzTryComponent>
<GraficoExternoU Data=@Datos />
</DnzTryComponent>Con fallback propio: el context es la Exception capturada, asi que puedes mostrar el motivo.
<DnzTryComponent>
<ChildContent>
<WidgetTercerosU Config=@Config />
</ChildContent>
<ErrorContent>
<RadzenAlert AlertStyle="AlertStyle.Danger" ShowIcon="true">
No se pudo cargar el widget: @context.Message
</RadzenAlert>
</ErrorContent>
</DnzTryComponent>El componente expone un metodo Recover() por referencia (@ref) para reintentar el render tras un fallo, util si das al usuario un boton de "Reintentar":
<DnzTryComponent @ref="boundary">
<ChildContent>
<WidgetTercerosU Config=@Config />
</ChildContent>
<ErrorContent>
<div class="d-flex flex-column align-items-center gap-2 p-3">
<span>El widget fallo: @context.Message</span>
<RadzenButton Text="Reintentar" Click=@(() => boundary.Recover()) />
</div>
</ErrorContent>
</DnzTryComponent>
@code {
private DnzTryComponent boundary;
}Parametros
| Parametro | Tipo | Por defecto | Que hace |
|---|---|---|---|
ChildContent | RenderFragment | El contenido que se renderiza dentro del limite de error. Obligatorio (EditorRequired) | |
ErrorContent | RenderFragment<Exception> | Fallback que se pinta si el ChildContent lanza una excepcion. El context es la Exception capturada. Si no lo pasas, no se muestra nada en su lugar |
DnzTryComponent tiene tambien un metodo publico Recover() (accesible por @ref) que reintenta renderizar el ChildContent despues de un fallo. Combinalo con un boton "Reintentar" en tu ErrorContent.
Relacionado
- Dialogos —
DnzSkeletones el patron tipico mientras el cuerpo de un dialogo carga sus datos - Tablas e informes — donde mas rinde el diferido y los skeletons al pintar listados pesados
- KPIs y metricas — el caso de uso clasico del revelado progresivo con
DnzDeferredContent - Cookbook de patrones — recetas de extremo a extremo que combinan estos componentes con el SDK
- Indice de componentes · Intro DinaZen
- SDK .NET · Cliente Dinaup — trae los datos que estos componentes cubren mientras cargan
- Informes de Dinaup Flex — la fuente de datos que suele estar detras de un loader o un skeleton
Inputs y formularios
Inputs para capturar y editar datos: búsqueda con debounce, subida de ficheros, editor de texto rico, editor de imagen, listas de etiquetas, pares clave/valor, pasos y el formulario dinámico de Flex.
Vistas avanzadas
Componentes especializados fuera del CRUD: línea de tiempo Gantt, código resaltado para documentar dentro de la app y selectores de rango de fechas con presets.