Como sabéis, a no ser que se especifique lo contrario mediante la directiva @inherits
, los componentes Blazor heredan de Microsoft.AspNetCore.Components.ComponentBase
. Esta clase abstracta proporcionada por el framework hace que podamos centrarnos en escribir nuestro código, al encargarse de gestionar aspectos básicos de los componentes como su creación, inicialización, renderizado, el ciclo de vida u otros aspectos de infraestructura.
Pero aunque heredar de ComponentBase
es la inmensa mayoría de las veces la mejor opción, no tiene por qué ser así necesariamente. Blazor reconoce como componente cualquier clase que implemente IComponent
, una pieza mucho más pequeña.
La interfaz IComponent
Todos los componentes Blazor implementan IComponent
, definido en el espacio de nombres Microsoft.AspNetCore.Components
de la siguiente forma:
public interface IComponent
{
void Attach(RenderHandle renderHandle);
Task SetParametersAsync(ParameterView parameters);
}
Como podéis observar, la interfaz se reduce a dos métodos:
Attach()
, que es invocado cuando el elemento es introducido en el DOM.SetParametersAsync()
, invocado tras el anterior, al cargar los parámetros por primera vez, y cada vez que se modifique el valor de éstos.
Dicho esto, veamos el ejemplo más sencillo posible que usa esta interfaz. El componente HelloWorld
mostrará el clásico saludo cuando sea introducido en el DOM de una página:
<h1><HelloWorld /></h1>
Su código fuente:
public class HelloWorld : IComponent
{
public void Attach(RenderHandle renderHandle)
{
renderHandle.Render(builder => builder.AddContent(1, "Hello, world!"));
}
public Task SetParametersAsync(ParameterView parameters) => Task.CompletedTask;
}
El método Render()
del RenderHandle
recibe como parámetro un RenderFragment
que, como ya hemos visto, es un delegado que permite "escribir" el contenido que será insertado en el DOM al renderizar el componente. En este caso, hemos escrito el delegado en forma de lambda que recibe el RenderTreeBuilder
para generar el contenido.
De esta forma, al llamar a Render()
en el método Attach()
, estamos forzando a que el contenido sea renderizado justo en el momento en que el componente es insertado en el DOM.
Vamos a complicar algo más el componente añadiéndole un parámetro que permita indicar un nombre al que saludar. Como podemos comprobar, sigue siendo bastante sencillo:
public class HelloWorld : IComponent
{
private RenderHandle _renderHandle;
public void Attach(RenderHandle renderHandle)
{
_renderHandle = renderHandle;
}
public Task SetParametersAsync(ParameterView parameters)
{
var name = parameters.GetValueOrDefault<string>("Name") ?? "World";
_renderHandle.Render(builder => builder.AddContent(1, $"Hello, {name}!"));
return Task.CompletedTask;
}
}
Fijaos que en este caso hemos desplazado el renderizado al método SetParametersAsync()
, que es donde se establecen los parámetros una vez ha sido creado el componente. Para ello hemos tenido que almacenar localmente el RenderHandle
suministrado a Attach()
.
Este componente podría usarse ahora de esta manera:
<h1><HelloWorld /></h1> <!-- Muestra Hello, World! -->
<h1><HelloWorld Name="Jon" /></h1> <!-- Muestra Hello, Jon! -->
Estos serían ejemplos de los componentes más simples que podemos implementar, lo más pegado al metal que Blazor nos permite. Sobre estos mimbres está construido ComponentBase
y todo lo que, sobre él, vayamos montando en nuestras aplicaciones.
¿Y es esto útil en la práctica? Pues no mucho más allá de satisfacer nuestra curiosidad y saber cómo funcionan las cosas por dentro 😉. Salvando algunas excepciones de componentes no visuales que no requieran ciclo de vida ni nada de lo que ComponentBase
nos facilita, no puedo imaginar casos en los que esta fórmula para construir componentes pueda resultar útil en nuestro día a día.
Pero bueno, ¿y lo que aprendemos por el camino?
Publicado en Variable not found.
Aún no hay comentarios, ¡sé el primero!
Enviar un nuevo comentario