Die übergeordnete Blazor-Komponente wird nach einem Klickereignis im untergeordneten Element unerwartet neu initialisiert

Aug 15 2020

Ich habe also eine übergeordnete und eine untergeordnete Komponente in einer Blazor-Server-App. Die übergeordnete Komponente befindet sich auf der Seite index.razor. Es sind keine Parameter erforderlich. Die untergeordnete Komponente hat eine Liste als Parameter:

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

Im übergeordneten Element gibt es ein Formular mit einer Schaltfläche, die etwas tut und eine Liste erstellt. Anschließend wird diese Liste als Parameter an die untergeordnete Komponente übergeben:

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

}

Die SearchPeople-Methode funktioniert einwandfrei und gibt die richtigen Daten zurück. Ich habe das Programm getestet und es sieht so aus, als würde die untergeordnete Komponente mit der Liste ordnungsgemäß erstellt. In einigen Fällen habe ich sogar gesehen, dass es für eine Sekunde auf der Seite auftaucht. Danach wird die übergeordnete Komponente jedoch vollständig neu initialisiert und alle Eigenschaften werden auf die Standardeinstellungen zurückgesetzt. Ich habe eine gesetzt

protected async override Task OnInitializedAsync() {
}

Methodenaufruf in der übergeordneten Komponente und ein Haltepunkt dort, und sicher wird er irgendwann nach dem Ereignis onclick aufgerufen. Die übergeordnete Komponente wird also definitiv jedes Mal gelöscht und neu initialisiert, wenn ich auf die Schaltfläche klicke.

Meine Frage ist also, warum Blazor die übergeordnete Komponente neu initialisieren sollte. Ich habe den Rat dieses Beitrags befolgt und bin mir nicht sicher, was ich anders mache: Wie kann ich eine List als Parameter an eine untergeordnete Komponente in Blazor übergeben?

Ich dachte, es könnte vielleicht an der Tatsache liegen, dass ich einen veränderlichen Parameter an das Kind übergebe, und wenn das Kind ihn mutiert, meint Blazor, dass der Elternteil neu initialisiert werden sollte, aber der Parameter lebt im Elternteil, so dass dies nicht der Fall wäre macht keinen Sinn.

Antworten

HenkHolterman Aug 15 2020 at 21:57

Sie haben ein verstecktes async voidund aus diesem Grund ist das erneute Rendern nicht synchron.

Ändern Sie diese Zeile

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

zu:

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

und du willst wahrscheinlich type="button"dort. Nicht das Hauptproblem.


Wenn Sie ein Benutzerereignis wie @onclick behandeln, führt Blazor nach dem Handler ein implizites StateHasChanged () aus, wodurch die Seite erneut gerendert wird.

SearchPeople () ist eine asynchrone Methode, die im ursprünglichen Ereignishandler jedoch nicht erwartet wurde. Es wurde also im Feuer-und-Vergessen-Modus betrieben und das erneute Rendern erfolgte, bevor die Methode abgeschlossen war.

PeterMorris Aug 15 2020 at 23:25

Ich gehe davon aus, dass sich Ihr Elternteil in einem befindet EditFormund Sie dessen ModelParameter ändern . Dadurch werden alle darin enthaltenen Komponenten zerstört und neu erstellt.

JamesHoux Dec 19 2020 at 02:29

Ich hatte eine Schaltfläche in einem Formular mit einem OnClick-Ereignis, das eine leere Methode aufrief - ja, es hat überhaupt nichts getan. Durch Klicken auf die Schaltfläche wurde die gesamte Seite zusammen mit allen Komponenten neu initialisiert, und nichts, was ich versucht habe, würde dieses Verhalten stoppen. Die Lösung bestand darin, das Formular-Tag einfach zu entfernen.

Dies ist eine seltsame Einschränkung, wie offenbar mit Formularen in Blazor umgegangen wird.

Vorschlag: Verwenden Sie Formulare überhaupt nicht, es sei denn, Ihre Implementierung ruft dies definitiv auf.