El componente principal de Blazor se reinicializa inesperadamente después del evento onclick en el elemento secundario
Entonces, tengo un componente principal y secundario en una aplicación de servidor Blazor. El componente principal está en la página index.razor No necesita parámetros. El componente hijo tiene una lista como parámetro:
...
@if (People == null)
{
<p><em>Loading...</em></p>
}
else
{
<li>
@foreach (var p in People)
{
<ul>@p.LastName, @p.FirstName</ul>
}
</li>
}
@code {
[Parameter]
public IReadOnlyList<PersonModel> People { get; set; }
}
...
En el padre, hay un formulario con un botón que hace algo y crea una lista, luego pasa esta lista como parámetro al componente hijo:
...
<button class="btn btn-outline-primary" type="submit" @onclick="(() => SearchPeople(firstNameInput, lastNameInput))">Search</button>
...
@if(peopleResults != null)
{
<PeopleList People="peopleResults"></PeopleList>
}
@code {
private string lastNameInput = string.Empty;
private string firstNameInput = string.Empty;
private List<PersonModel> peopleResults {
get;
set; }
private async Task SearchPeople(string lastName, string firstName)
{
peopleResults = await _personData.SearchPeopleByName(firstName, lastName);
}
}
El método SearchPeople funciona bien y devuelve los datos correctos. He depurado el programa y parece que empieza a construir el componente secundario con la Lista correctamente. De hecho, en algunos casos lo he visto aparecer en la página por un segundo. Sin embargo, después de eso, el componente principal se reinicializa por completo y todas las propiedades vuelven a sus valores predeterminados. He puesto un
protected async override Task OnInitializedAsync() {
}
llamada al método en el componente principal y un punto de interrupción allí, y efectivamente se llama en algún momento después del evento onclick. Entonces, el componente principal definitivamente se borra y reinicializa cada vez que hago clic en el botón.
Entonces, mi pregunta es, ¿por qué blazor reinicializaría el componente principal? Seguí el consejo de esta publicación para esto, y no estoy seguro de qué estoy haciendo de manera diferente: ¿Cómo puedo pasar una List
Pensé que tal vez podría deberse al hecho de que le estoy pasando un parámetro mutable al niño, y si el niño lo muta, blazor piensa que el padre debería reinicializarse, pero el parámetro vive en el padre, por lo que no no tiene sentido.
Respuestas
Tiene un oculto async void
y, debido a eso, la reproducción no está sincronizada.
Cambiar esta linea
<button class="btn btn-outline-primary" type="submit"
@onclick="(() => SearchPeople(firstNameInput, lastNameInput))">Search</button>
a:
<button class="btn btn-outline-primary" type="submit"
@onclick="(async () => await SearchPeople(firstNameInput, lastNameInput))">Search</button>
y probablemente quieras type="button"
allí. No es el problema principal.
Cuando maneja un evento de usuario como @onclick, Blazor hará un StateHasChanged () implícito después del controlador, lo que provocará una nueva representación de la página.
SearchPeople () es un método asincrónico pero en el controlador de eventos original no se esperaba. Así que operó en modo de disparar y olvidar y la rendición ocurrió antes de que se completara el método.
Supongo que su padre está dentro de un EditForm
y está cambiando su Model
parámetro. Eso hace que todos los componentes dentro de él sean destruidos y recreados.
Tenía un botón en un formulario con un evento OnClick que llamaba a un método vacío ; sí, no hizo nada en absoluto. Al hacer clic en el botón, toda la página se reinicializa junto con todos sus componentes, y nada de lo que intenté detendría este comportamiento. La solución fue simplemente deshacerse de la etiqueta del formulario.
Esta es una advertencia extraña sobre cómo se manejan los formularios en Blazor aparentemente.
Sugerencia: No use Formularios en absoluto a menos que su implementación definitivamente lo llame.