다음을 통해 공유


ASP.NET Core에서 매개 변수 덮어쓰기 방지 Blazor

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Warning

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조 하세요. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

로버트 하켄

이 문서에서는 다시 렌더링하는 동안 앱에서 Blazor 매개 변수를 덮어쓰지 않도록 하는 방법을 설명합니다.

덮어쓴 매개 변수

Blazor 프레임워크는 일반적으로 안전한 부모-자식 매개 변수 할당을 적용합니다.

  • 매개 변수는 예기치 않게 덮어쓰지 않습니다.
  • 부작용이 최소화됩니다. 예를 들어 추가 렌더링은 무한 렌더링 루프를 만들 수 있으므로 피합니다.

자식 구성 요소는 부모 구성 요소가 렌더링될 때 기존 값을 덮어쓸 수 있는 새 매개 변수 값을 받습니다. 자식 구성 요소의 매개 변수 값을 실수로 덮어쓰게 되면 하나 이상의 데이터 바인딩 매개 변수가 있는 구성 요소를 개발하고 개발자가 자식의 매개 변수에 직접 쓸 때 종종 발생합니다.

  • 자식 구성 요소는 부모 구성 요소의 매개 변수 값을 하나 이상 사용하여 렌더링됩니다.
  • 자식은 매개 변수 값에 직접 씁니다.
  • 부모 구성 요소는 자식 매개 변수의 값을 렌더링하고 덮어씁니다.

매개 변수 값을 덮어쓸 수 있는 가능성은 자식 구성 요소의 속성 set 접근자로도 확장됩니다.

Important

구성 요소가 처음으로 렌더링된 후에는 고유한 매개 변수에 직접 쓰는 구성 요소를 만들지 않는 것이 일반적인 지침입니다.

다음을 수행하는 ShowMoreExpander 구성 요소를 고려해 보세요.

  • 제목을 렌더링합니다.
  • 선택한 경우 자식 콘텐츠를 표시합니다.
  • 구성 요소 매개 변수(InitiallyExpanded)를 사용하여 초기 상태를 설정할 수 있습니다.

다음 ShowMoreExpander 구성 요소가 덮어쓴 매개 변수를 보여 준 다음 이 시나리오에 적합한 방법을 보여 주기 위해 수정된 ShowMoreExpander 구성 요소가 표시됩니다. 다음 예제를 로컬 샘플 앱에 배치하여 설명된 동작을 경험할 수 있습니다.

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

StateHasChanged를 호출할 수 있는 다음 Expanders 부모 구성 요소에 ShowMoreExpander 구성 요소를 추가합니다.

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>

처음에 ShowMoreExpander 구성 요소는 속성이 설정되면 독립적으로 InitiallyExpanded 동작합니다. 자식 구성 요소는 상태를 예상대로 유지합니다.

StateHasChanged가 부모 구성 요소에서 호출되면 Blazor 프레임워크는 매개 변수가 변경되었을 수 있는 경우 자식 구성 요소를 다시 렌더링합니다.

  • Blazor가 명시적으로 검사하는 매개 변수 형식의 그룹에 대해 Blazor는 매개 변수가 변경된 것을 감지하면 자식 구성 요소를 다시 렌더링합니다.
  • 선택되지 않은 매개 변수 형식에 대해 Blazor는 매개 변수가 변경되었는지 여부에 관계없이 자식 구성 요소를 다시 렌더링합니다. 자식 콘텐츠는 다른 변경 가능한 개체를 참조하는 대리자인 RenderFragment형식이므로 이 매개 변수 형식 범주에 속합니다.

Expanders 구성 요소:

  • 첫 번째 ShowMoreExpander 구성 요소는 잠재적으로 변경 가능한 RenderFragment에 자식 콘텐츠를 설정하므로 부모 구성 요소에서 StateHasChanged를 호출하면 구성 요소가 자동으로 다시 렌더링되고 InitiallyExpanded 값을 false의 초기 값으로 덮어쓰게 됩니다.
  • 두 번째 ShowMoreExpander 구성 요소는 자식 콘텐츠를 설정하지 않습니다. 따라서 잠재적으로 변경 가능한 RenderFragment가 없습니다. 부모 구성 요소에서 StateHasChanged를 호출해도 자식 구성 요소를 자동으로 다시 렌더링하지 않으므로 구성 요소의 InitiallyExpanded 값을 덮어쓰지 않습니다.

이전 시나리오에서 상태를 유지하려면 구성 요소의 ShowMoreExpander 프라이빗 필드를 사용하여 상태를 유지합니다.

다음은 수정된 ShowMoreExpander 구성 요소입니다.

  • 부모의 InitiallyExpanded 구성 요소 매개 변수 값을 허용합니다.
  • OnInitialized 이벤트에서 구성 요소 매개 변수 값을 ‘private 필드’(expanded)에 할당합니다.
  • 프라이빗 필드를 사용하여 내부 설정/해제 상태를 유지합니다. 이 상태는 매개 변수에 직접 쓰는 것을 방지하는 방법을 보여줍니다.

참고 항목

이 섹션의 조언은 구성 요소 매개 변수set 접근자의 유사한 논리까지 확장되어 원치 않는 부작용이 발생할 수 있습니다.

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

참고 항목

수정된 ShowMoreExpander 내용은 초기화 후 매개 변수의 InitiallyExpanded 변경 내용을 반영하지 않습니다(OnInitialized). 특정 시나리오에서 이미 초기화된 구성 요소는 새 매개 변수 값을 받을 수 있습니다. 예를 들어 동일한 구성 요소가 다른 세부 정보 보기를 렌더링하는 데 사용되는 기본 하위 뷰에서 또는 경로 매개 변수가 변경되어 다른 항목을 표시할 때 /item/{id} 발생할 수 있습니다.

다음 구성 요소를 고려합니다.ToggleExpander

  • 내부 및 외부에서 상태를 변경할 수 있습니다.
  • 동일한 구성 요소 인스턴스를 다시 사용하는 경우에도 새 매개 변수 값을 처리합니다.

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

ToggleExpander 매개 변수의 양방향 동기화를 @bind-Expanded="{field}" 허용하는 바인딩 구문과 함께 구성 요소를 사용해야 합니다.

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

부모-자식 바인딩에 대한 자세한 내용은 다음 리소스를 참조하세요.

Blazor가 검사하는 정확한 형식에 대한 정보를 포함하여 변경 내용 검색에 대한 자세한 내용은 ASP.NET Core Razor 구성 요소 렌더링을 참조하세요.