Quantcast
Channel: Planeta Código
Viewing all articles
Browse latest Browse all 2715

Variable not found: Crear bloques de código Razor reutilizables en Blazor con Render Fragments

$
0
0
Blazor

Durante la implementación de páginas o componentes Blazor en archivos .razor, es relativamente frecuente encontrarse con casos en los que nos interesa reutilizar un bloque de código Razor en más de un punto. 

Por ejemplo, observad el siguiente código:

<h1>Todo list</h1>
<h2>Pending tasks</h2>
<ul>
@foreach (TodoItem item in TodoItems.Where(i=>!i.IsDone).OrderBy(i=>i.Priority))
{
<li>@item.Task, owned by @item.Owner and created at @item.CreatedAt</li>
}
</ul>
<h2>Finished tasks</h2>
<ul>
@foreach (TodoItem item in TodoItems.Where(i=>i.IsDone).OrderBy(i=>i.DateFinished))
{
<li>@item.Task, owned by @item.Owner and created at @item.CreatedAt</li>
}
</ul>

En el código anterior, podemos ver claramente que estamos repitiendo los dos bloques de código encargados de mostrar los elementos de cada una de las listas, por lo que, si en el futuro quisiéramos cambiar la forma de mostrar un TodoItem, tendríamos que modificar el interior de los dos bloques. Es frecuente en estos casos optar por crear un nuevo componente que se encargue de ello, por ejemplo, llamado TodoListItem:

<li>@Item.Task, owned by @Item.Owner and created at @Item.CreatedAt</li>
@code {
[Parameter]
public TodoItem Item { get; set;}
}

De esta forma ya tendremos el código de renderización del TodoItem centralizado y podremos simplificar el bloque anterior eliminando la duplicidad:

<h1>Todo list</h1>
<h2>Pending tasks</h2>
<ul>
@foreach (TodoItem item in TodoItems.Where(i=>!i.IsDone).OrderBy(i=>i.Priority))
{
<TodoListItem Item="item" />
}
</ul>
<h2>Finished tasks</h2>
<ul>
@foreach (TodoItem item in TodoItems.Where(i=>i.IsDone).OrderBy(i=>i.DateFinished))
{
<TodoListItem Item="item" />
}
</ul>

Aunque conceptualmente la solución que hemos implementado es correcta, introduce un problema en nuestra aplicación: por el mero hecho de querer evitar la duplicación de código, estamos introduciendo en la página un número indeterminado de componentes, lo cual podría afectar drásticamente a su rendimiento.

Por llevarlo al extremo, imaginad que esas listas tienen miles de elementos. En este caso, en nuestra página estaríamos introduciendo miles de componentes, con lo que esto implica:

  • Deberían instanciarse miles de componentes (objetos).
  • Deberían ejecutarse los eventos del ciclo de vida de cada componente al crearlos, inicializarlos, renderizarlos, etc.
  • Mientras se encuentren en la página cada componente ocuparía memoria, ya sea en cliente (Blazor WebAssembly) o en servidor (Blazor Server).

Esto podría llegar incluso a hacer una página inutilizable, por lo que es importante disponer de otros métodos para crear y reutilizar bloques de código HTML sin necesidad de crear componentes. Esta es una de las utilidades de los render fragments.

Introducing Render Fragments

Los fragmentos de renderización, o render fragments, son delegados reutilizables que permiten introducir contenido en páginas u otros componentes Blazor. Los hemos visto ya algunas veces por aquí, como cuando echamos un vistazo a los componentes con cuerpo y componentes genéricos.

Estos delegados reciben como parámetro un objeto de tipo RenderTreeBuilder, usado para configurar el contenido que deseamos insertar en la página cuando son invocados. Por ejemplo, el siguiente código muestra cómo crear un render fragment que muestra la hora actual, y cómo puede ser invocado desde el cuerpo de una página Blazor:

@page "/time"
<p>La hora actual es: @CurrentTime</p>
<p>Y vuelvo a repetirla: @CurrentTime</p>
...
@code {
private RenderFragment CurrentTime = builder =>
{
builder.AddMarkupContent(1, "<time>" + DateTime.Now + "</time>");
};
}

Podéis leer más sobre la generación de componentes usando RenderTreeBuilder en este post de Chris Sainty.

El código anterior es lo suficientemente claro y fácil de escribir, pero aún podemos mejorarlo. Gracias a la magia del tooling de Blazor, es posible introducir código Razor directamente en el cuerpo del delegado, por lo que podríamos simplificarlo de esta forma:

@code {
private RenderFragment CurrentTime = __builder =>
{
<time>@DateTime.Now</time>
};
}

Por convención, el parámetro RenderTreeBuilder del delegado debe llamarse __builder. En caso contrario, fallará en compilación.

Estos miembros pueden ser también estáticos, por lo que podrían ser compartidos entre distintos componentes. Por ejemplo, si creásemos un archivo llamado Utils.razor con el siguiente código, todos los componentes podrían usar nuestro render fragment simplemente haciendo referencia a él a través su clase (@Utils.CurrentTime):

@* Archivo Utils.razor *@
@code {
public static RenderFragment CurrentTime = __builder =>
{
<time>@DateTime.Now</time>
};
}

Los ejemplos anteriores eran bastante sencillos, porque el contenido no dependía de ningún valor externo, pero también es posible enviar al delegado datos para que los utilice a la hora de componer la salida.

Por ejemplo, volviendo al ejemplo con el que comenzamos este post, tiene bastante sentido enviar al delegado un objeto de tipo TodoItem para generar la descripción de cada tarea, para lo que utilizaremos en esta ocasión el tipo RenderFragment<TodoItem>:

@code {
private RenderFragment<TodoItem> ItemView = item => __builder =>
{
<li>
@item.Task, owned by @item.Owner and created at @item.CreatedAt
</li>
};
}

La sintaxis es algo más compleja, pero básicamente se trata de un delegado que acepta un parámetro de tipo TodoItem, y retorna otro delegado, que ya es el que recibe el RenderTreeBuilder y define el contenido a retornar.

Para utilizar este fragmento parametrizado bastaría con suministrarle el valor en el momento de realizar la llamada:

<h1>Todo list</h1>
<h2>Pending tasks</h2>
<ul>
@foreach (TodoItem item in TodoItems.Where(i=>!i.IsDone).OrderBy(i=>i.Priority))
{
@ItemView(item)
}
</ul>
<h2>Finished tasks</h2>
<ul>
@foreach (TodoItem item in TodoItems.Where(i=>i.IsDone).OrderBy(i=>i.DateFinished))
{
@ItemView(item)
}
</ul>

¡Y esto es todo! Espero que os haya resultado interesante y os sea de utilidad para mejorar vuestras aplicaciones Blazor :)

Publicado en: www.variablenotfound.com.

Viewing all articles
Browse latest Browse all 2715

Trending Articles


Girasoles para colorear


mayabang Quotes, Torpe Quotes, tanga Quotes


Tagalog Quotes About Crush – Tagalog Love Quotes


OFW quotes : Pinoy Tagalog Quotes


Long Distance Relationship Tagalog Love Quotes


Tagalog Quotes To Move on and More Love Love Love Quotes


5 Tagalog Relationship Rules


Best Crush Tagalog Quotes And Sayings 2017


Re:Mutton Pies (lleechef)


FORECLOSURE OF REAL ESTATE MORTGAGE


Sapos para colorear


tagalog love Quotes – Tiwala Quotes


Break up Quotes Tagalog Love Quote – Broken Hearted Quotes Tagalog


Patama Quotes : Tagalog Inspirational Quotes


Pamatay na Banat and Mga Patama Love Quotes


Tagalog Long Distance Relationship Love Quotes


BARKADA TAGALOG QUOTES


“BAHAY KUBO HUGOT”


Vimeo 10.7.0 by Vimeo.com, Inc.


Vimeo 10.7.1 by Vimeo.com, Inc.