ASP.NET Core'da parametrelerin üzerine yazmaktan kaçının Blazor
Uyarı
ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.
Tarafından Robert Haken
Bu makalede, yeniden oluşturma sırasında uygulamalarda parametrelerin Blazor üzerine yazılmasını önleme açıklanmaktadır.
Üzerine yazılan parametreler
Blazor çerçevesi genellikle güvenli bir üst-alt parametre ataması uygular:
- Beklenmedik bir şekilde parametrelerin üzerine yazılmaz.
- Yan etkiler en aza indirilir. Örneğin ek işlemelerden kaçınılır çünkü bunlar sonsuz işleme döngüleri oluşturabilir.
Alt bileşen, üst bileşen yeniden işlendiğinde büyük olasılıkla mevcut değerlerin üzerine yazılacak yeni parametre değerleri alır. Bileşen bir veya birden fazla veri bağlama parametresiyle geliştirildiğinde ve geliştirici doğrudan alt bileşendeki parametrenin üzerine yazdığında, yanlışlıkla alt bileşendeki parametre değerlerinin üzerine yazılması durumu oluşur:
- Alt bileşen üst bileşenden bir veya birden fazla parametre değeriyle işlenir.
- Alt bileşen doğrudan parametrenin değerine yazar.
- Üst bileşen yeniden işlenir ve alt bileşenin parametre değerinin üzerine yazar.
Parametre değerlerinin üzerine yazma olasılığı alt bileşenin set
özellik erişimcilerine de yayılır.
Önemli
Genel önerimiz bileşen ilk kez işlendikten sonra doğrudan kendi parametrelerine yazan bileşenler oluşturmak değildir.
Aşağıdaki ShowMoreExpander
bileşenini düşünün:
- Başlığı işler.
- Seçildiğinde alt içeriği gösterir.
- Bir bileşen parametresi (
InitiallyExpanded
) ile ilk durumu ayarlamanıza olanak tanır.
Aşağıdaki ShowMoreExpander
bileşeni üzerine yazılmış bir parametreyi gösterdikten sonra, bu senaryodaki doğru yaklaşımı ortaya koymak için değiştirilmiş bir ShowMoreExpander
bileşeni gösteriliyor. Açıklanan davranışları deneyimlemek için aşağıdaki örnekler yerel bir uygulama örneğine yerleştirilebilir.
ShowMoreExpander.razor
:
<div @onclick="ShowMore" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @InitiallyExpanded)</h2>
</div>
@if (InitiallyExpanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private void ShowMore() => InitiallyExpanded = true;
}
<div @onclick="ShowMore" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @InitiallyExpanded)</h2>
</div>
@if (InitiallyExpanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private void ShowMore() => InitiallyExpanded = true;
}
<div @onclick="ShowMore" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @InitiallyExpanded)</h2>
</div>
@if (InitiallyExpanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private void ShowMore()
{
InitiallyExpanded = true;
}
}
<div @onclick="ShowMore" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @InitiallyExpanded)</h2>
</div>
@if (InitiallyExpanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private void ShowMore()
{
InitiallyExpanded = true;
}
}
<div @onclick="ShowMore" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @InitiallyExpanded)</h2>
</div>
@if (InitiallyExpanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
private void ShowMore()
{
InitiallyExpanded = true;
}
}
<div @onclick="ShowMore" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @InitiallyExpanded)</h2>
</div>
@if (InitiallyExpanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
private void ShowMore()
{
InitiallyExpanded = true;
}
}
ShowMoreExpander
bileşeni, StateHasChanged yöntemini çağırabilecek aşağıdaki Expanders
üst bileşenine eklenir:
- Geliştirici kodunda çağırmak StateHasChanged , bir bileşenin durumunun değiştiğini bildirir ve genellikle kullanıcı arabirimini güncelleştirmek için bileşen yeniden kayıt işlemini sıralar. StateHasChanged yöntemi daha sonra ASP.NET Core Razor bileşeni yaşam döngüsü ve ASP.NET Core Razor bileşenini işleme bölümlerinde daha ayrıntılı açıklanır.
- Düğmenin
@onclick
yönerge özniteliği düğmeninonclick
olayına bir olay işleyicisi ekler. Olay işleyicisi daha sonra ASP.NET Core Blazor olay işleyicisi bölümünde daha ayrıntılı açıklanır.
Expanders.razor
:
@page "/expanders"
<PageTitle>Expanders</PageTitle>
<h1>Expanders Example</h1>
<ShowMoreExpander InitiallyExpanded="false">
Expander 1 content
</ShowMoreExpander>
<ShowMoreExpander InitiallyExpanded="false" />
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@page "/expanders"
<PageTitle>Expanders</PageTitle>
<h1>Expanders Example</h1>
<ShowMoreExpander InitiallyExpanded="false">
Expander 1 content
</ShowMoreExpander>
<ShowMoreExpander InitiallyExpanded="false" />
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@page "/expanders"
<PageTitle>Expanders</PageTitle>
<h1>Expanders Example</h1>
<ShowMoreExpander InitiallyExpanded="false">
Expander 1 content
</ShowMoreExpander>
<ShowMoreExpander InitiallyExpanded="false" />
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@page "/expanders"
<PageTitle>Expanders</PageTitle>
<h1>Expanders Example</h1>
<ShowMoreExpander InitiallyExpanded="false">
Expander 1 content
</ShowMoreExpander>
<ShowMoreExpander InitiallyExpanded="false" />
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@page "/expanders"
<h1>Expanders Example</h1>
<ShowMoreExpander InitiallyExpanded="false">
Expander 1 content
</ShowMoreExpander>
<ShowMoreExpander InitiallyExpanded="false" />
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@page "/expanders"
<h1>Expanders Example</h1>
<ShowMoreExpander InitiallyExpanded="false">
Expander 1 content
</ShowMoreExpander>
<ShowMoreExpander InitiallyExpanded="false" />
<button @onclick="StateHasChanged">Call StateHasChanged</button>
Başlangıçta, ShowMoreExpander
özellikleri ayarlandığında bileşenler bağımsız olarak InitiallyExpanded
davranır. Alt bileşenler beklendiği gibi durumlarını korur.
Üst bileşende StateHasChanged yöntemi çağrılırsa Blazor çerçevesi parametreleri değişmiş olabilecek alt bileşenleri yeniden işler:
- Blazor'ın açıkça denetlediği bir grup parametre türü için, Blazor parametrelerden herhangi birinin değiştiğini algılarsa alt bileşeni yeniden işler.
- Denetlenmeyen parametre türleri için, Blazor parametrelerin değişip değişmediğine bakılmaksızın alt bileşeni yeniden işler. Alt içerik, diğer değiştirilebilir nesnelere başvuran bir temsilci olan RenderFragment türünde olduğundan bu parametre türleri kategorisinde yer alır.
Expanders
bileşeni için:
- İlk
ShowMoreExpander
bileşen, alt içeriği büyük olasılıkla değiştirilebilir RenderFragmentbir içinde ayarlar, bu nedenle üst bileşendeki çağrısı StateHasChanged bileşeni otomatik olarak yeniden oluşturur ve değerininInitiallyExpanded
false
üzerine yazılabilir. - İkinci
ShowMoreExpander
bileşeni alt içerik ayarlamaz. Bu nedenle potansiyel olarak değiştirilebilir bir RenderFragment türü yoktur. Üst bileşende yapılan StateHasChanged çağrısı alt bileşeni otomatik olarak yeniden işlemez, dolayısıyla bileşeninInitiallyExpanded
değerinin üzerine yazılmaz.
Önceki senaryoda durumu korumak için, bileşende ShowMoreExpander
durumunu korumak için özel bir alan kullanın.
Aşağıdaki düzeltilmiş ShowMoreExpander
bileşeni:
- Üst bileşenden
InitiallyExpanded
bileşen parametresi değerini kabul eder. OnInitialized
olayında bileşen parametre değerini bir özel alana atar (expanded
).- İç geçiş durumunu korumak için özel alanı kullanır ve bu da doğrudan parametrenin üzerine yazmanın nasıl önleneceğini gösterir.
Not
Bu bölümdeki öneri, buna benzer istenmeyen yan etkilere neden olabilecek bileşen parametresi set
erişimcilerindeki benzer mantığı da kapsar.
ShowMoreExpander.razor
:
<div @onclick="Expand" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
private bool expanded;
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
protected override void OnInitialized() => expanded = InitiallyExpanded;
private void Expand() => expanded = true;
}
<div @onclick="Expand" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
private bool expanded;
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
protected override void OnInitialized() => expanded = InitiallyExpanded;
private void Expand() => expanded = true;
}
<div @onclick="Expand" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
private bool expanded;
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
protected override void OnInitialized()
{
expanded = InitiallyExpanded;
}
private void Expand()
{
expanded = true;
}
}
<div @onclick="Expand" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
private bool expanded;
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
protected override void OnInitialized()
{
expanded = InitiallyExpanded;
}
private void Expand()
{
expanded = true;
}
}
<div @onclick="Expand" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
private bool expanded;
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
protected override void OnInitialized()
{
expanded = InitiallyExpanded;
}
private void Expand()
{
expanded = true;
}
}
<div @onclick="Expand" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
private bool expanded;
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
protected override void OnInitialized()
{
expanded = InitiallyExpanded;
}
private void Expand()
{
expanded = true;
}
}
Not
DüzeltilenShowMoreExpander
, başlatmadanOnInitialized
() sonra parametrede InitiallyExpanded
yapılan değişiklikleri yansıtmaz. Bazı senaryolarda, zaten başlatılmış bir bileşen yeni parametre değerleri alabilir. Bu durum, örneğin, aynı bileşenin farklı ayrıntı görünümlerini işlemek için kullanıldığı birincil-alt görünümde veya yol parametresi farklı bir öğeyi görüntüleyecek şekilde değiştiğinde /item/{id}
oluşabilir.
Aşağıdaki ToggleExpander
bileşeni göz önünde bulundurun:
- Durumu hem içeriden hem de dışarıdan değiştirmenize olanak tanır.
- Aynı bileşen örneği yeniden kullanılasa bile yeni parametre değerlerini işler.
ToggleExpander.razor
:
<div class="card bg-light mb-3" style="width:30rem">
<div @onclick="Toggle" class="card-header">
<h2 class="card-title">Toggle (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool Expanded { get; set; }
[Parameter]
public EventCallback<bool> ExpandedChanged { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private bool expanded;
protected override void OnParametersSet() => expanded = Expanded;
private async void Toggle()
{
expanded = !expanded;
await ExpandedChanged.InvokeAsync(expanded);
}
}
<div class="card bg-light mb-3" style="width:30rem">
<div @onclick="Toggle" class="card-header">
<h2 class="card-title">Toggle (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool Expanded { get; set; }
[Parameter]
public EventCallback<bool> ExpandedChanged { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private bool expanded;
protected override void OnParametersSet() => expanded = Expanded;
private async void Toggle()
{
expanded = !expanded;
await ExpandedChanged.InvokeAsync(expanded);
}
}
<div class="card bg-light mb-3" style="width:30rem">
<div @onclick="Toggle" class="card-header">
<h2 class="card-title">Toggle (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool Expanded { get; set; }
[Parameter]
public EventCallback<bool> ExpandedChanged { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private bool expanded;
protected override void OnParametersSet()
{
expanded = Expanded;
}
private async void Toggle()
{
expanded = !expanded;
await ExpandedChanged.InvokeAsync(expanded);
}
}
<div class="card bg-light mb-3" style="width:30rem">
<div @onclick="Toggle" class="card-header">
<h2 class="card-title">Toggle (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool Expanded { get; set; }
[Parameter]
public EventCallback<bool> ExpandedChanged { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private bool expanded;
protected override void OnParametersSet()
{
expanded = Expanded;
}
private async void Toggle()
{
expanded = !expanded;
await ExpandedChanged.InvokeAsync(expanded);
}
}
<div class="card bg-light mb-3" style="width:30rem">
<div @onclick="Toggle" class="card-header">
<h2 class="card-title">Toggle (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool Expanded { get; set; }
[Parameter]
public EventCallback<bool> ExpandedChanged { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
private bool expanded;
protected override void OnParametersSet()
{
expanded = Expanded;
}
private async void Toggle()
{
expanded = !expanded;
await ExpandedChanged.InvokeAsync(expanded);
}
}
<div class="card bg-light mb-3" style="width:30rem">
<div @onclick="Toggle" class="card-header">
<h2 class="card-title">Toggle (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool Expanded { get; set; }
[Parameter]
public EventCallback<bool> ExpandedChanged { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
private bool expanded;
protected override void OnParametersSet()
{
expanded = Expanded;
}
private async void Toggle()
{
expanded = !expanded;
await ExpandedChanged.InvokeAsync(expanded);
}
}
Bileşenin ToggleExpander
bağlama söz dizimi ile kullanılması, parametrenin @bind-Expanded="{field}"
iki yönlü eşitlenmesine izin verilmelidir.
ExpandersToggle.razor
:
@page "/expanders-toggle"
<PageTitle>Expanders Toggle</PageTitle>
<h1>Expanders Toggle</h1>
<ToggleExpander @bind-Expanded="expanded">
Expander content
</ToggleExpander>
<button @onclick="Toggle">Toggle</button>
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@code {
private bool expanded;
private void Toggle() => expanded = !expanded;
}
@page "/expanders-toggle"
<PageTitle>Expanders Toggle</PageTitle>
<h1>Expanders Toggle</h1>
<ToggleExpander @bind-Expanded="expanded">
Expander content
</ToggleExpander>
<button @onclick="Toggle">Toggle</button>
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@code {
private bool expanded;
private void Toggle() => expanded = !expanded;
}
@page "/expanders-toggle"
<PageTitle>Expanders Toggle</PageTitle>
<h1>Expanders Toggle</h1>
<ToggleExpander @bind-Expanded="expanded">
Expander content
</ToggleExpander>
<button @onclick="Toggle">Toggle</button>
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@code {
private bool expanded;
private void Toggle()
{
expanded = !expanded;
}
}
@page "/expanders-toggle"
<PageTitle>Expanders Toggle</PageTitle>
<h1>Expanders Toggle</h1>
<ToggleExpander @bind-Expanded="expanded">
Expander content
</ToggleExpander>
<button @onclick="Toggle">Toggle</button>
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@code {
private bool expanded;
private void Toggle()
{
expanded = !expanded;
}
}
@page "/expanders-toggle"
<h1>Expanders Toggle</h1>
<ToggleExpander @bind-Expanded="expanded">
Expander content
</ToggleExpander>
<button @onclick="Toggle">Toggle</button>
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@code {
private bool expanded;
private void Toggle()
{
expanded = !expanded;
}
}
@page "/expanders-toggle"
<h1>Expanders Toggle</h1>
<ToggleExpander @bind-Expanded="expanded">
Expander content
</ToggleExpander>
<button @onclick="Toggle">Toggle</button>
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@code {
private bool expanded;
private void Toggle()
{
expanded = !expanded;
}
}
Üst-alt bağlama hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın:
- Bileşen parametreleriyle bağlama
- İkiden fazla bileşen arasında bağlama
- Blazor İki Yönlü Bağlama Hatası (dotnet/aspnetcore #24599)
Tam olarak denetleen Blazor türler hakkında bilgiler de dahil olmak üzere değişiklik algılama hakkında daha fazla bilgi için bkz . ASP.NET Core Razor bileşeni işleme.
ASP.NET Core