컴포넌트 매개변수
[Parameter] 특성을 사용해 부모에서 자식 컴포넌트로 데이터를 전달하는 방법을 학습합니다.
📌 학습 목표
[Parameter]특성의 역할과 사용 목적을 설명할 수 있습니다.- 부모 컴포넌트에서 자식 컴포넌트로 string, int, bool, 객체 등 다양한 타입을 전달할 수 있습니다.
EventCallback을 사용하여 자식에서 부모로 이벤트를 역전달할 수 있습니다.RenderFragment로 컴포넌트 태그 사이에 HTML 슬롯을 구현할 수 있습니다.[CascadingParameter]로 깊은 계층의 컴포넌트에 데이터를 전달할 수 있습니다.
📝 개념 설명
컴포넌트 매개변수란?
Blazor에서 컴포넌트 매개변수(Component Parameter)는 부모 컴포넌트가 자식 컴포넌트에게 데이터를 전달하는 핵심 메커니즘입니다. HTML 태그의 속성(attribute)처럼 값을 설정하면, 자식 컴포넌트는 [Parameter] 특성이 붙은 public 프로퍼티를 통해 해당 값을 수신합니다.
React의 props, Angular의 @Input()과 유사한 개념으로, Blazor 컴포넌트 아키텍처의 기본 데이터 흐름 방식입니다.
(값 설정)
(HTML 속성으로 전달)
([Parameter] 수신)
(UI 업데이트)
[Parameter] 특성 기본 규칙
- 프로퍼티는 반드시
public접근 제한자여야 합니다. [Parameter]특성은Microsoft.AspNetCore.Components네임스페이스에 포함되어 있으며, Razor 파일에서는 자동으로 포함됩니다.@code { }블록 안에 선언합니다.- 매개변수 이름은 HTML 속성명과 대소문자를 구분하지 않지만, 관례상 PascalCase를 사용합니다.
- 기본값을 지정할 수 있으며, 부모가 해당 속성을 전달하지 않으면 기본값이 적용됩니다.
💡 예제 & 실습
예제 1 — 기본 string 매개변수 전달
가장 단순한 형태로, 부모에서 자식 컴포넌트에 문자열을 전달하는 예제입니다.
@* Greeting.razor *@
<div class='greeting-box'>
<h2>안녕하세요, @Name 님!</h2>
<p>오늘도 좋은 하루 되세요.</p>
</div>
@code {
[Parameter]
public string Name { get; set; } = "이름 없음";
}
@page "/"
<h1>인사말 컴포넌트 테스트</h1>
<Greeting Name="홍길동" />
<Greeting Name="김철수" />
<Greeting /> @* Name 생략 → 기본값 "이름 없음" 적용 *@
<Greeting> 태그마다 별도의 인스턴스가 생성되며, Name 값에 따라 다른 인사말이 렌더링됩니다. 마지막 태그처럼 속성을 생략하면 기본값 “이름 없음”이 출력됩니다.
예제 2 — 여러 타입의 매개변수
string, int, bool 등 여러 타입을 함께 사용하는 실전 예제입니다.
@* ProductCard.razor *@
<div class='product-card'>
<h3>@ProductName</h3>
<p>가격: @Price.ToString("N0")원</p>
@if (IsOnSale)
{
<span class='badge'>세일 중!</span>
}
</div>
@code {
[Parameter]
public string ProductName { get; set; } = string.Empty;
[Parameter]
public int Price { get; set; }
[Parameter]
public bool IsOnSale { get; set; }
}
@page "/"
<ProductCard ProductName="블레이저 입문서"
Price="25000"
IsOnSale="true" />
<ProductCard ProductName="C# 고급편"
Price="38000" /> @* IsOnSale 생략 → 기본값 false *@
IsOnSale을 속성값 없이 단독으로 쓰면 IsOnSale="true"와 동일합니다. 속성 자체를 생략하면 기본값 false가 적용됩니다.
예제 3 — EventCallback으로 역방향 통신
자식 컴포넌트에서 발생한 이벤트를 부모에게 전달하는 패턴입니다. Blazor의 단방향 데이터 흐름 철학을 따릅니다.
@* Counter.razor *@
<button @onclick="HandleClick">클릭 횟수: @Count</button>
@code {
[Parameter]
public int Count { get; set; }
[Parameter]
public EventCallback<int> OnCountChanged { get; set; }
private async Task HandleClick()
{
Count++;
await OnCountChanged.InvokeAsync(Count);
}
}
@page "/"
<p>부모가 받은 카운트: @parentCount</p>
<Counter Count="@parentCount" OnCountChanged="HandleCountChanged" />
@code {
private int parentCount = 0;
private void HandleCountChanged(int newCount)
{
parentCount = newCount;
}
}
예제 4 — RenderFragment (콘텐츠 슬롯)
자식 컴포넌트의 여는 태그와 닫는 태그 사이에 임의의 HTML을 삽입하는 고급 패턴입니다.
@* Card.razor — 래퍼 컴포넌트 *@
<div class='card'>
<div class='card-header'>@Title</div>
<div class='card-body'>
@ChildContent
</div>
</div>
@code {
[Parameter]
public string Title { get; set; } = string.Empty;
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
<Card Title="공지사항">
<p>이 내용은 카드 안에 표시됩니다.</p>
<strong>굵은 텍스트도 가능합니다.</strong>
</Card>
RenderFragment 타입 매개변수의 이름이 정확히 ChildContent일 때, 컴포넌트 태그 사이의 모든 마크업이 자동으로 전달됩니다. 이름이 다를 경우 부모에서 명시적 중첩 태그로 지정해야 합니다.
예제 5 — CascadingParameter (계단식 전달)
여러 컴포넌트 계층을 건너뛰어 깊은 자손 컴포넌트에 데이터를 전달할 때 사용합니다. 매 계층마다 [Parameter]를 반복 전달하는 prop drilling 문제를 해결합니다.
@* App.razor 또는 Layout 컴포넌트 *@
<CascadingValue Value="currentTheme">
<Router AppAssembly="@typeof(App).Assembly">
...자식 컴포넌트 트리...
</Router>
</CascadingValue>
@code {
private string currentTheme = "dark";
}
@code {
[CascadingParameter]
public string Theme { get; set; } = "light";
}
CascadingValue로 감싼 범위 안의 모든 컴포넌트가 선언만 하면 자동으로 수신합니다.
⚠️ 자주 틀리는 것 / 주의사항
1. public이 없는 프로퍼티에 [Parameter] 사용
// ❌ 잘못된 예 — private은 외부에서 접근 불가, 컴파일 경고 발생
[Parameter]
private string Name { get; set; }
// ✅ 올바른 예
[Parameter]
public string Name { get; set; } = string.Empty;
2. [Parameter] 프로퍼티를 자식이 직접 수정
// ❌ 잘못된 예 — 부모의 값과 충돌하여 다음 렌더링 시 원복됨
private void ChangeTitle()
{
Title = "새 제목"; // [Parameter] 프로퍼티 직접 변경 금지
}
// ✅ 올바른 예 — 내부 상태를 별도 변수로 복사하여 관리
private string internalTitle = string.Empty;
protected override void OnParametersSet()
{
internalTitle = Title; // 매개변수 변경 시 내부 복사본 갱신
}
3. EventCallback과 Action 혼동
| 항목 | EventCallback<T> | Action / Func<T> |
|---|---|---|
| UI 자동 갱신 | ✅ StateHasChanged 자동 호출 | ❌ 수동 호출 필요 |
| 비동기 지원 | ✅ InvokeAsync 내장 | ⚠️ 별도 처리 필요 |
| 예외 처리 | ✅ Blazor 에러 경계 통합 | ❌ 직접 처리 |
| 컴포넌트 이벤트 권장 | ✅ 권장 | ❌ 사용 지양 |
4. null 허용 타입 처리 누락
// ⚠️ 참조 타입 매개변수는 null이 될 수 있음
[Parameter]
public string? OptionalName { get; set; }
// 렌더링 시 null 체크 필수
<p>@(OptionalName ?? "기본 이름")</p>
5. [Parameter]와 [SupplyParameterFromQuery] 혼동
[Parameter]는 부모 컴포넌트에서 전달받는 값이고, [SupplyParameterFromQuery]는 URL 쿼리 스트링(?id=123)에서 값을 가져옵니다. 데이터 소스가 완전히 다르므로 혼용하지 않도록 주의합니다.
🎯 마무리
컴포넌트 매개변수는 Blazor 애플리케이션에서 컴포넌트 간 데이터를 주고받는 핵심 메커니즘입니다. [Parameter]로 단순 값을 전달하고, EventCallback으로 역방향 이벤트를 처리하며, RenderFragment로 콘텐츠 슬롯을 구현하는 세 가지 패턴을 조합하면 재사용 가능하고 유연한 컴포넌트를 설계할 수 있습니다.
실전 팁: 컴포넌트를 설계할 때는 “외부에서 무엇을 받아야 동작하는가”를 먼저 정의하세요. 매개변수가 많아질수록 컴포넌트의 재사용성이 낮아지므로, 꼭 필요한 매개변수만 공개하는 것이 좋습니다.
[Parameter]특성은 public 프로퍼티에만 적용 가능하며, 부모가 HTML 속성처럼 값을 전달합니다.- string, int, bool, 객체 등 C#의 모든 타입을 매개변수로 사용할 수 있습니다.
- 기본값은 프로퍼티 초기화(
= 기본값)로 지정하며, 부모가 속성을 생략하면 기본값이 적용됩니다. EventCallback<T>는 자식→부모 역방향 통신을 담당하며, StateHasChanged 자동 호출로 UI를 갱신합니다.RenderFragment ChildContent는 컴포넌트 태그 사이의 HTML 마크업을 슬롯으로 수신합니다.[CascadingParameter]는<CascadingValue>로 감싼 범위 안의 모든 자손 컴포넌트에 값을 전달합니다.- [Parameter] 프로퍼티를 자식이 직접 수정하면 안 되며, 내부 복사본 패턴 또는 EventCallback을 사용합니다.