La .NET CONF 2024 acaba de terminar. Descubre las NOVEDADES de .NET 9 junto a los CAMBIOS que trae C# 13.
Puedes ver el contenido de este vídeo junto con su curso en el modo vídeo (similar a Udemy) si pulsas aquí.

Ciclo de vida de los componentes en blazor

En este post vamos a ver como funciona el ciclo de vida de los componentes de blazor y los métodos con los que podemos trabajar en el ciclo de vida. 

 

1 - Inyección de dependencias con Blazor

Para este post es importante que tengas claro el concepto de inyección de dependencias, la lógica es igual que para C#. 

Te dejo los enlaces que necesitas entender antes de continuar con este post

 

Únicamente hay un aspecto que difiere entre blazor y C# “normal” y es que en C# normalmente inyectamos las dependencias en el constructor de nuestra clase. 

Pero en blazor, como vimos en el post de los componentes en blazor no disponemos de un constructor por lo que debemos injectarla utilizando @inject dentro de nuestro fichero .razor o [Inject] en nuestra partial class.

 

En  nuestro caso inyectamos IHttpClientFactory quedándonos de una de las siguiente formas:

//PerfilPersonal.razor
@inject IHttpClientFactory ClientFactory

//PerfilPersonal.razor.cs
[Inject]
private IHttpClientFactory ClientFactory { get; set; }

 

 

2 - Llamadas HTTP con Blazor

Para realizar llamadas HTTP con blazor seguiremos la misma lógica que en C# para ello utilizaremos IHttpClientFactory, si no estás familiarizado con las llamadas HTTP te recomiendo que te leas el siguiente post

La única diferencia que podemos encontrar, es que si utilizamos .NET5 podemos importar el paquete using System.Net.Http.Json y deserializar automaticamente nuestra response. 

var client = ClientFactory.CreateClient("BackendApi");
return await client.GetFromJsonAsync<ResultDto<PersonalProfileDto>>($"api/perfilpersonal/{profileCode}");

 

3 - Ciclo de vida de los componentes 

Cuando hablamos de blazor, hablamos de componentes, pequeñas piezas de código

Antes de continuar decir que estos métodos pueden ser tanto síncronos como asíncronos en este caso como estamos llamando a un servicio externo, serán asíncronos. 

Para este ejemplo vamos a consultar en el back-end nuestro perfil personal, el cual va a ser parte de la url, para acceder simplemente utilizamos https://localhost:44363/perfil/{nombre}

 

Pero cómo recibimos estos valores?

Primero de todo es recordar del post anterior que con la directiva @page podemos pasar un parámetro de la url.

Debemos coger este parámetro y enviarlo a nuestro componente donde imprimimos la información, ya que es en el componente donde haremos la llamada HTTP. 

@page "/perfil/{Name}"
@using WebPersonal.FrontEnd.WebApp.Componentes

<PerfilPersonal Profile="@Name"></PerfilPersonal>

@code{
    [Parameter]
    public string Name { get; set; }
}

Ahora debemos saber cómo tratar este parámetro  para que el funcionamiento de nuestra página funcione como esperamos

 

3.1 - SetParameterAsync

El método SetParameterAsync es el que primero se ejecuta cuando un componente se crea. Todos los parámetros enviados al componente se almacenan dentro del tipo ParameterView así que si queremos realizar alguna acción antes de que los parámetros sean asignados aquí lo podemos hacer.

public override Task SetParametersAsync(ParameterView parameters)
{
    return base.SetParametersAsync(parameters);
}

 

3.2 - OnInitialized y OnInitializedAsync

Estos métodos se ejecutan justo cuando el componente se inicializa. 

protected override void OnInitialized()
{
    base.OnInitialized();
}
protected override Task OnInitializedAsync()
{
    return base.OnInitializedAsync();
}

Es importante tener en cuenta que estos método solo se ejecutan una vez por componente. 

 

3.3. - OnParameterSet y OnParameterSetAsync

Estos métodos se ejecutan cuando después de recibir los parámetros los valores son asignados a las propiedades, y se ejecutan cada vez que los parámetros son actualizados. 

protected override void OnParametersSet()
{
    base.OnParametersSet();
}
protected override Task OnParametersSetAsync()
{
    return base.OnParametersSetAsync();
}

 

3.4 - OnAfterRender y OnAfterRenderAsync

En el momento en el que el componente termina de renderizar, estos métodos se ejecutan. 

protected override void OnAfterRender(bool firstRender)
{
    base.OnAfterRender(firstRender);
}
protected override Task OnAfterRenderAsync(bool firstRender)
{
    return base.OnAfterRenderAsync(firstRender);
}

 

3.5 - StateHasChanged

Es el método que debemos llamar cuando cambiamos algo en nuestro componente para que este se vuelva a renderizar. Por ejemplo si quieres mostrar u ocultar un modal debes volver a renderizar el componente.

 

3.6 - ShouldRender

Con este método podemos bloquear que la interfaz de usuario se refresque ya que es llamado cada vez que renderizamos el componente, eso sí, aunque devolvemos `false` si es la primera vez que renderizamos el componente lo renderiza igual

 

3.7 - Dispose

Como nota adicional, indicar que podemos implementar IDisposable en nuestra clase, y por lo tanto deberemos implementar el método Dispose.

Si no sabes cómo implementar dispose, mira el siguiente enlace:

 

 

4 - Ejemplo de ciclo de vida de un componente en blazor

Para este ejemplo vamos a ir a algo muy común, leer de un perfil a otro. Sería similar a cambiar posts en un blog.

Para el ejemplo vamos a usar el proyecto que hemos venido usando hasta ahora que está disponible en el enlace a GitHub de este mismo post.  

 

Por lo tanto, ejecutaremos una llamada a https://localhost:44363/perfil/{nombre}

Lo primero que tenemos que tener claro, es que el componente va a empezar a asignar valores y renderizar cuando `SetParameterAsync` finaliza, esto que quiere decir, que si tenemos que realizar llamadas a servicios externos (por ejemplo para leer el perfil completo) no podemos acceder hasta que dicha llamada haya terminado. 

hablando en código, si tenemos algo como lo siguiente:

<div>
    <div class="row">
        <div class="col-sm-12 text-center">@PersonalProfile.FirstName @PersonalProfile.LastName</div>
    </div>
</div>

Asumimos que nos va a imprimir el nombre y el apellido, pero esto no es así ya que PersonalProfile es null, por lo tanto nos salta una excepción.

 

Debemos esperar a que PersonalProfile tenga un valor para poder imprimir la información.

@if (PersonalProfile != null)
{
    <div>
        <div class="row">
            <div class="col-sm-12 text-center">@PersonalProfile.FirstName @PersonalProfile.LastName</div>
        </div>
    </div>
}

 

Nota: también podemos utilizar el "coalesce value" @(PersonalProfile?.FirstName ?? "").

 

4.1 - Dónde llamar a un servicio externo desde blazor

Ya tenemos claro que antes de imprimir nada debemos asignar el valor a la propiedad PersonalProfile. Dónde lo hacemos?

Lo primero que nos viene a la mente es hacerlo dentro de  OnInitializedAsync ya que es el método que se ejecuta cuando inicializamos el componente.

protected override async Task OnInitializedAsync()
{
    var result = await GetPersonalProfile(Profile);
    if (!result.Errors.Any())
        PersonalProfile = result.Value;
    else
        Erros = result.Errors;
}

private async Task<ResultDto<PersonalProfileDto>> GetPersonalProfile(string profileCode)
{
    var client = ClientFactory.CreateClient("BackendApi");
    return await client.GetFromJsonAsync<ResultDto<PersonalProfileDto>>($"api/perfilpersonal/{profileCode}", new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true
    });
}

Y técnicamente funciona, o eso parece. 

Vamos a comprobar como esta no es la solución buena. 

Si añadimos un segundo perfil, lo ponemos en un enlace al final de nuestra página y pulsamos este mismo enlace podremos observar como la url cambia pero el contenido sigue siendo el mismo. 

<a href="/perfil/netmentor"> Enlace al segundo perfile</a>

ciclo de vida blazor 1

Esto es debido a que OnInitializedAsync solo se ejecuta una única vez por componente y para nuestro routing tanto /perfil/ivanabad como /perfil/netmentor son el mismo componente ya que ambos entran dentro de /perfil/{Nombre}.

 

Para que la información se actualice, debemos realizar la llamada a nuestro `Back-End` dentro de OnParameterSet u OnParameterSetAsync, esto es debido a que como hemos mencionado, el componente no cambia, solo cambia el parámetro.

 

Para implementar el ciclo de vida de forma correcta lo que vamos a hacer es crear una propiedad privada la cual va a contener el valor de nuestro  parámetro Perfil, pero no lo recibiremos como tal, sino que lo asignaremos del que viene como parámetro, esto lo hacemos para comprobar si el parámetro ha cambiado o es el mismo, y si ha cambiado volver a recargar.

 

Puedes ver la implementación en la siguiente pieza de código:

public partial class PerfilPersonal
{
    [Inject]
    private IHttpClientFactory ClientFactory { get; set; }
    [Parameter]
    public string Profile { get; set; }
    private string _profileValue { get; set; } //Propiedad privada para almacenar el valor actual
    public PersonalProfileDto PersonalProfile { get; set; }
    public List<ErrorDto> Erros { get; set; }

    protected override async Task OnParametersSetAsync()
    {
        if (_profileValue != Profile) //Comparamos el valor, y si es distinto, consultamos la información
        {
            await CalculateProfile();
        }

        await base.OnParametersSetAsync();
    }

    private async Task CalculateProfile()
    {
        _profileValue = Profile; //ASignamos el valor
        var result = await GetPersonalProfile(Profile);
        if (!result.Errors.Any())
            PersonalProfile = result.Value;
        else
            Erros = result.Errors;
    }

    private async Task<ResultDto<PersonalProfileDto>> GetPersonalProfile(string profileCode)
    {
        var client = ClientFactory.CreateClient("BackendApi");
        return await client.GetFromJsonAsync<ResultDto<PersonalProfileDto>>($"api/perfilpersonal/{profileCode}", new JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true
        });
    }
}

Debes realizar la misma implementación en todos los componentes que tienen un parámetro que puede cambiar.

ciclo de vida componente blazor

 

Conclusión

  •  En este post hemos visto que la inyección de dependencias en blazor es un pelín diferente a la inyección de dependencias en nuestras clases de C#.
  • Hemos visto que HttpClient funciona de la misma forma en blazor que en C#.
  • Hemos visto cómo funciona el ciclo de vida de los componentes en blazor y un ejemplo de cómo implementar un ciclo de vida de un componente.

 


Uso del bloqueador de anuncios adblock

Hola!

Primero de todo bienvenido a la web de NetMentor donde podrás aprender programación en C# y .NET desde un nivel de principiante hasta más avanzado.


Yo entiendo que utilices un bloqueador de anuncios como AdBlock, Ublock o el propio navegador Brave. Pero te tengo que pedir por favor que desactives el bloqueador para esta web.


Intento personalmente no poner mucha publicidad, la justa para pagar el servidor y por supuesto que no sea intrusiva; Si pese a ello piensas que es intrusiva siempre me puedes escribir por privado o por Twitter a @NetMentorTW.


Si ya lo has desactivado, por favor recarga la página.


Un saludo y muchas gracias por tu colaboración

© copyright 2024 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café