Il componente padre di Blazer viene reinizializzato in modo imprevisto dopo l'evento onclick nel figlio
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
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
Hai un nascosto async void
e 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.
Mi aspetto che il tuo genitore sia all'interno di un EditForm
e tu stia cambiando il suo Model
parametro. Ciò fa sì che tutti i componenti al suo interno vengano distrutti e ricreati.
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.