Un parámetro de componente es una propiedad pública que recibe un valor desde el componente padre.
Los parámetros permiten crear componentes configurables y reutilizables. En Blazor, los declaramos con [Parameter] y los asignamos desde el marcado del padre.
Este flujo de datos es fundamental en el diseño de interfaces modernas y sigue un patrón estricto: One-Way Data Binding (enlace unidireccional). Los datos fluyen hacia abajo, del padre al hijo.
El atributo [Parameter]
Para convertir una propiedad normal de una clase C# en un parámetro que pueda recibir valores desde HTML, simplemente debemos decorarla con el atributo [Parameter].
Vamos a retomar nuestro ejemplo de la tarjeta de usuario, pero esta vez haciéndola dinámica.
Definición en el hijo (UserCard.razor)
<div class="card" style="border-color: @BorderColor">
<h3>@Title</h3>
<p>Edad: @Age</p>
</div>
@code {
// Para que una propiedad sea un parámetro, debe ser:
// 1. Pública
// 2. Tener { get; set; }
// 3. Llevar el atributo [Parameter]
[Parameter]
public string Title { get; set; } = "Usuario Anónimo"; // Valor por defecto
[Parameter]
public int Age { get; set; }
[Parameter]
public string BorderColor { get; set; } = "gray";
}Es una buena práctica inicializar las propiedades con valores por defecto. Si el padre no envía el dato, el componente no fallará ni mostrará espacios vacíos feos.
Uso en el padre (Home.razor)
Ahora, desde el componente padre, podemos establecer estos valores utilizando atributos HTML que coinciden con los nombres de nuestras propiedades.
@page "/"
<h1>Usuarios del sistema</h1>
<UserCard Title="Luis Llamas" BorderColor="blue" />
<UserCard Title="Ana García" Age="@(25 + 5)" />
<UserCard Title="@currentUser" Age="currentAge" />
@code {
private string currentUser = "Pedro";
private int currentAge = 40;
}Fíjate en la diferencia:
- Un
stringliteral se escribe directamente:Title="Luis". - Para una expresión delimitada se usa
@(...):Age="@(25 + 5)". - En parámetros cuyo tipo no es
string, Blazor interpreta el valor como C# y normalmente no necesita@:Age="currentAge". Para distinguir una variable de un literal en un parámetrostring, sí usamosTitle="@currentUser".
Cómo pasar objetos complejos
En aplicaciones reales (LOB), rara vez pasamos propiedades sueltas (Nombre, Edad, Email…). Lo normal es pasar un objeto completo (un Modelo o DTO).
Blazor maneja esto perfectamente.
El Modelo:
public class Usuario
{
public string Nombre { get; set; }
public string Email { get; set; }
public bool IsActive { get; set; }
}El Hijo (UserCard.razor):
<div class="card @(UserData.IsActive ? "bg-light" : "bg-warning")">
<h4>@UserData.Nombre</h4>
<small>@UserData.Email</small>
</div>
@code {
[Parameter]
public Usuario UserData { get; set; } = default!; // Recibimos el objeto entero
}El Padre:
<UserCard UserData="myUser" />
@code {
private Usuario myUser = new Usuario
{
Nombre = "Carlos",
Email = "[email protected]",
IsActive = true
};
}Parámetros obligatorios con [EditorRequired]
A veces, un componente no tiene sentido sin un parámetro específico. Por ejemplo, una tarjeta de usuario sin usuario.
Desde .NET 6, podemos usar el atributo [EditorRequired] para indicar a Visual Studio que nos avise si olvidamos pasar ese parámetro.
[Parameter, EditorRequired]
public Usuario UserData { get; set; } = default!;Si usamos <UserCard /> sin pasar UserData, las herramientas de compilación muestran una advertencia. [EditorRequired] no valida el valor en tiempo de ejecución, así que debes mantener también la nulabilidad y las comprobaciones apropiadas.
Úsalo cuando el parámetro sea indispensable para que el componente funcione. Así queda claro qué datos exige el componente.
No sobrescribir parámetros
Como criterio general, no escribas en un [Parameter] después del primer renderizado. El padre puede volver a asignarlo cuando renderice de nuevo y pisar el cambio local.
// ⛔ MAL: Modificando un parámetro internamente
private void Cumpleanos()
{
// Si el padre renderiza de nuevo, este valor se sobrescribirá
// con el valor original que tiene el padre.
Age++;
}En el flujo “One-Way”, el dueño del dato es el Padre. El Hijo solo lo recibe para mostrarlo.
- Si el padre cambia el valor, el hijo se actualiza automáticamente (
OnParametersSet). - Si el hijo necesita cambiar el dato, debe avisar al padre (mediante Eventos, que veremos más adelante) para que el padre lo cambie.
Si modificas el parámetro en el hijo, crearás estados inconsistentes y bugs difíciles de rastrear donde los datos “vuelven atrás” misteriosamente.
Parámetros de ruta
Aunque técnicamente son un tema de Routing, merece la pena mencionar que también se usan atributos [Parameter] para leer datos de la URL.
Si tenemos @page "/usuario/{Id}", podemos capturar ese Id así:
@page "/usuario/{Id}"
<h3>Viendo usuario: @Id</h3>
@code {
[Parameter]
public string Id { get; set; }
}Blazor es inteligente: al ver que la propiedad Id coincide con el segmento {Id} de la ruta, inyecta el valor automáticamente.
Resumen
El atributo [Parameter] es la tubería por la que viajan los datos en nuestra aplicación.
- Usamos
[Parameter]en propiedades públicas del componente hijo. - Los datos fluyen Padre -> Hijo.
- Podemos pasar tipos simples u objetos complejos.
- Usamos
[EditorRequired]para advertir de que falta un parámetro requerido. - No modificamos los parámetros dentro del hijo; respetamos la fuente de la verdad.
¿Y si queremos pasar trozos de HTML u otros componentes en lugar de datos como cadenas, números u objetos? Por ejemplo, una ventana modal que admita cualquier contenido.
Para eso, los parámetros normales no sirven. Necesitamos algo más potente: los RenderFragments, y es el tema de nuestro próximo artículo.