blazor-ciclo-de-vida-componentes

Ciclo de vida en Blazor: métodos y orden de ejecución

  • 5 min

El ciclo de vida de un componente Blazor es la secuencia de métodos que se ejecutan durante su creación, actualización, renderizado y retirada.

Como desarrolladores, necesitamos intervenir en momentos precisos de esta existencia:

  • ¿Cuándo cargo los datos de la base de datos?
  • ¿Cuándo recalculo variables si el padre cambia un parámetro?
  • ¿Cuándo puedo llamar a una librería de JavaScript para pintar un gráfico?

Para intervenir en esos momentos, Blazor ofrece métodos virtuales que podemos sobrescribir.

MétodoCuándo correObjetivo principal
OnInitializedAl inicializar la instanciaCargar datos iniciales que no dependen de cambios en parámetros.
OnParametersSet1 vez + cada cambio de parámetrosRecalcular datos basados en parámetros (ProductId, SearchTerm).
OnAfterRenderDespués de cada renderizado interactivoLlamar a JavaScript, enfocar controles o desplazar la página.
DisposeAl retirar el componenteCancelar tareas y limpiar eventos o temporizadores.

El flujo general

Antes de entrar en detalle, veamos la secuencia de ejecución estándar cuando un componente se renderiza:

Instanciación: Se crea la clase (Constructor).

SetParametersAsync: Se inyectan los parámetros.

OnInitialized{Async}: Se inicializa el componente.

OnParametersSetAsync: El componente recibe/actualiza datos.

OnAfterRender{Async}: La interfaz interactiva ya se ha actualizado.

Vamos a analizar los tres pilares fundamentales que usarás en el 99% de tus componentes.


OnInitialized y OnInitializedAsync

Este método se ejecuta al inicializar una instancia, después de que haya recibido sus parámetros iniciales. En una aplicación con prerenderizado, la inicialización puede ejecutarse dos veces: una para generar el HTML en el servidor y otra al comenzar el renderizado interactivo.

Es el equivalente al constructor, pero con una diferencia crucial: en el constructor, los [Parameter] y las inyecciones de dependencia (@inject) aún no están listos. En OnInitialized, sí.

¿Para qué lo usamos? Principalmente para cargar datos iniciales de una base de datos o API.

@inject IUserService UserService

<h3>Perfil de @User?.Name</h3>

@code {
    private UserDto User;

    protected override async Task OnInitializedAsync()
    {
        // Simulamos una llamada a base de datos
        // Hacemos esto aquí y no en el constructor
        User = await UserService.GetUserByIdAsync(1);
    }
}
Copied!

Usa la variante asíncrona (OnInitializedAsync) cuando esperes una API, una base de datos u otra operación de E/S. Evita bloquear el contexto de ejecución del componente con trabajo síncrono lento.


OnParametersSet y OnParametersSetAsync

En este punto es fácil cometer errores.

Este método se ejecuta:

  1. Inmediatamente después de OnInitialized.
  2. Cuando el padre vuelve a proporcionar parámetros. Para tipos complejos, Blazor puede tratarlos como modificados aunque la referencia parezca la misma.

¿Para qué lo usamos? Para reaccionar a cambios. Imagina un componente que muestra detalles de un producto basado en un Id que le pasa el padre.

  • Si cargas el producto en OnInitialized, solo funcionará la primera vez.
  • Si el usuario cambia de producto sin salir de la página, OnInitialized no se volverá a ejecutar, pero OnParametersSet .
<h3>Detalle Producto: @Product?.Name</h3>

@code {
    [Parameter]
    public int ProductId { get; set; }

    private ProductDto Product;

    // Se ejecuta cada vez que ProductId cambia
    protected override async Task OnParametersSetAsync()
    {
        Product = await ProductService.GetByIdAsync(ProductId);
    }
}
Copied!
  • Si la carga de datos depende solo de la creación del componente, usa OnInitialized.
  • Si la carga de datos depende de un [Parameter] que puede cambiar, usa OnParametersSet.

OnAfterRender y OnAfterRenderAsync

Este método se ejecuta después de un renderizado interactivo, cuando los cambios ya se han aplicado al DOM y están disponibles las referencias a elementos y componentes. No se ejecuta durante el prerenderizado ni durante SSR estático.

Este método recibe un booleano firstRender:

  • true: Es la primera vez que se pinta el componente.
  • false: Son actualizaciones posteriores.

¿Para qué lo usamos? Principalmente para inicialización que necesita el contenido ya renderizado, como interactuar con JavaScript mediante JS Interop.

Antes de este punto, los elementos HTML no existen en el navegador. Si intentas llamar a una función JS para pintar un mapa de Google Maps en OnInitialized, fallará porque el <div id="map"> aún no existe.

@inject IJSRuntime JS

<div id="mi-grafico"></div>

@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // Solo inicializamos librerías JS la primera vez
        if (firstRender)
        {
            await JS.InvokeVoidAsync("iniciarGrafico", "mi-grafico");
        }
    }
}
Copied!

Cuidado con los renderizados repetidos: Si llamas a StateHasChanged sin una condición dentro de OnAfterRender, programas otro renderizado y puedes crear un bucle. OnAfterRenderAsync no vuelve a renderizar automáticamente cuando termina su Task, precisamente para evitar este problema.

Liberar recursos con Dispose

Aunque no es un método del ciclo “de vida” activo, es importante para la “muerte”. Si tu componente se suscribe a eventos (de un servicio, por ejemplo) o crea timers, debes limpiarlos cuando el usuario abandona la pantalla.

Para ello, el componente debe implementar IDisposable o IAsyncDisposable.

@implements IDisposable

@code {
    protected override void OnInitialized()
    {
        MiServicio.OnCambio += ManejarCambio;
    }

    public void Dispose() // Se llama cuando Blazor retira el componente
    {
        // IMPORTANTE: Desuscribirse para evitar fugas de memoria
        MiServicio.OnCambio -= ManejarCambio;
    }
}
Copied!