Le composant parent Blazor est réinitialisé de manière inattendue après un événement onclick dans l'enfant

Aug 15 2020

Donc, j'ai un composant Parent et Enfant dans une application serveur Blazor. Le composant parent se trouve dans la page index.razor. Il ne prend aucun paramètre. Le composant enfant a une liste comme paramètre:

...
@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; }
}
...

Dans le parent, il y a un formulaire avec un bouton qui fait quelque chose et construit une liste, puis passe cette liste en tant que paramètre dans le composant enfant:

...
<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);
    }

}

La méthode SearchPeople fonctionne correctement et renvoie les données correctes. J'ai débogué le programme et il semble qu'il commence à créer correctement le composant enfant avec la liste. En fait, dans certains cas, je l'ai vu apparaître sur la page pendant une seconde. Cependant, après cela, le composant parent est complètement réinitialisé et toutes les propriétés sont réinitialisées aux valeurs par défaut. J'ai mis un

protected async override Task OnInitializedAsync() {
}

appel de méthode dans le composant parent et un point d'arrêt à l'intérieur, et bien sûr, il est appelé un certain point après l'événement onclick. Ainsi, le composant parent est définitivement effacé et réinitialisé chaque fois que je clique sur le bouton.

Ma question est donc la suivante: pourquoi blazor réinitialiserait-il le composant parent? J'ai suivi les conseils de cet article pour cela, et je ne suis pas sûr de ce que je fais différemment: Comment puis-je passer une List en tant que paramètre à un composant enfant dans Blazor?

Je pensais que cela pourrait être dû au fait que je transmettais un paramètre mutable à l'enfant, et si l'enfant le mute, blazor pense que le parent devrait être réinitialisé, mais le paramètre vit dans le parent, donc ce ne serait pas Ça n'a pas de sens.

Réponses

HenkHolterman Aug 15 2020 at 21:57

Vous avez un caché async voidet à cause de ce re-rendu est désynchronisé.

Changer cette ligne

<button class="btn btn-outline-primary" type="submit" 
  @onclick="(() => SearchPeople(firstNameInput, lastNameInput))">Search</button>

à:

<button class="btn btn-outline-primary" type="submit" 
  @onclick="(async () => await SearchPeople(firstNameInput, lastNameInput))">Search</button>

et vous voulez probablement type="button"là - bas. Pas le problème principal.


Lorsque vous gérez un événement utilisateur comme @onclick, Blazor fera un StateHasChanged () implicite après le gestionnaire, provoquant un nouveau rendu de la page.

SearchPeople () est une méthode asynchrone mais dans le gestionnaire d'événements d'origine, elle n'était pas attendue. Donc, il a fonctionné en mode feu et oublier et le rendu a eu lieu avant que la méthode ne soit terminée.

PeterMorris Aug 15 2020 at 23:25

Je suppose que votre parent est à l'intérieur d'un EditFormet que vous modifiez son Modelparamètre. Cela provoque la destruction et la recréation de tous les composants à l'intérieur.

JamesHoux Dec 19 2020 at 02:29

J'avais un bouton dans un formulaire avec un événement OnClick qui appelait une méthode vide - oui, cela ne faisait rien du tout. En cliquant sur le bouton, la page entière a été réinitialisée avec tous ses composants, et rien de ce que j'ai essayé n'arrêterait ce comportement. La solution consistait simplement à se débarrasser de la balise form.

C'est une mise en garde étrange avec la façon dont les formulaires sont gérés apparemment dans Blazor.

Suggestion: n'utilisez pas du tout Forms à moins que votre implémentation ne l'appelle définitivement.