Il componente padre di Blazer viene reinizializzato in modo imprevisto dopo l'evento onclick nel figlio

Aug 15 2020

Quindi, ho un componente padre e figlio in un'app server blazer. Il componente padre si trova nella pagina index.razor Non richiede parametri. Il componente figlio ha un elenco come parametro:

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

Nel genitore, c'è un modulo con un pulsante che fa qualcosa e costruisce un elenco, quindi passa questo elenco come parametro nel componente figlio:

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

}

Il metodo SearchPeople funziona bene e restituisce i dati corretti. Ho eseguito il debug del programma e sembra che inizi a costruire correttamente il componente figlio con l'elenco. In effetti, in alcuni casi l'ho visto apparire sulla pagina per un secondo. Tuttavia, in seguito, il componente padre viene completamente reinizializzato e tutte le proprietà vengono ripristinate ai valori predefiniti. Ho messo un file

protected async override Task OnInitializedAsync() {
}

chiamata al metodo nel componente genitore e un punto di interruzione lì, e abbastanza sicuro che viene chiamato un punto dopo l'evento onclick. Quindi il componente genitore viene sicuramente cancellato e reinizializzato ogni volta che faccio clic sul pulsante.

Quindi la mia domanda è: perché Blazor reinizializza il componente genitore? Ho seguito il consiglio di questo post per questo, e non sono sicuro di cosa sto facendo in modo diverso: come posso passare una lista come parametro a un componente figlio in blazor?

Ho pensato che potrebbe essere dovuto al fatto che sto passando un parametro modificabile al bambino, e se il bambino lo muta, Blazor pensa che il genitore dovrebbe essere reinizializzato, ma il param vive nel genitore, quindi non lo farebbe non ha senso.

Risposte

HenkHolterman Aug 15 2020 at 21:57

Hai un nascosto async voide per questo motivo il rendering non è sincronizzato.

Cambia questa linea

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

per:

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

e probabilmente type="button"ci vuoi . Non è il problema principale.


Quando gestisci un evento utente come @onclick Blazor eseguirà un StateHasChanged () implicito dopo il gestore, provocando un nuovo rendering della pagina.

SearchPeople () è un metodo asincrono ma nel gestore eventi originale non era atteso. Quindi ha funzionato in modalità spara e dimentica e il rendering è avvenuto prima che il metodo fosse completato.

PeterMorris Aug 15 2020 at 23:25

Mi aspetto che il tuo genitore sia all'interno di un EditForme tu stia cambiando il suo Modelparametro. Ciò fa sì che tutti i componenti al suo interno vengano distrutti e ricreati.

JamesHoux Dec 19 2020 at 02:29

Avevo un pulsante in un modulo con un evento OnClick che chiamava un metodo vuoto - sì, non ha fatto nulla. Facendo clic sul pulsante, l'intera pagina viene reinizializzata insieme a tutti i suoi componenti e nulla di ciò che ho provato avrebbe fermato questo comportamento. La soluzione era semplicemente eliminare il tag del modulo.

Questo è uno strano avvertimento su come apparentemente vengono gestiti i moduli in Blazor.

Suggerimento: non utilizzare affatto i moduli a meno che l'implementazione non lo chiami definitivamente.