.NET 9 및 .NET 10의 Blazor 상호 작용: 전체 가이드

· 12분 읽기

지난 몇 년 동안 Blazor를 사용하여 웹 애플리케이션을 구축해 왔다면 프레임워크가 발전했다는 것을 알 것입니다. Blazor Server와 Blazor WebAssembly 사이의 선택으로 시작된 것은 애플리케이션의 각 구성 요소에 대해 올바른 상호 작용 전략을 선택할 수 있는 유연한 통합 렌더링 모델로 발전했습니다.

.NET 8에서는 기본적으로 렌더링 모드와 정적 서버 측 렌더링(SSR)이 도입되었습니다. 이제 .NET 9 및 .NET 10은 개발자 환경을 보다 원활하게 만들고 최종 사용자 환경을 더욱 빠르게 만드는 개선 사항을 통해 이러한 기반 위에 구축되었습니다.

이 게시물에서는 렌더링 모드 작동 방식, 스트리밍 SSR이 테이블에 제공하는 것, 향상된 탐색 및 양식 처리가 게임을 어떻게 변화시키는지, 최신 릴리스의 새로운 기능 등 현재의 Blazor 상호 작용에 대한 전체 그림을 안내하고 싶습니다. 새로운 Blazor 프로젝트를 계획하고 있거나 업그레이드를 고려하고 있다면 이 가이드가 제가 이 모든 것을 파헤치기 시작할 때 갖고 싶었던 가이드입니다.

간략한 되돌아보기: 우리가 여기까지 온 과정

.NET 8 이전에는 프로젝트 수준에서 호스팅 모델을 커밋해야 했습니다. Blazor Server는 SignalR 연결을 통해 서버에서 모든 것이 실행됨을 의미합니다. Blazor WebAssembly는 모든 것이 브라우저에서 실행된다는 것을 의미했습니다. 각각에는 장단점이 있었고 이를 혼합하는 것은 고통스러웠습니다.

.NET 8은 두 모델을 통합하는 단일 프로젝트 템플릿인 Blazor Web App을 도입하여 판도를 바꾸었습니다. 핵심 개념은 렌더링 모드입니다. 구성 요소별로 렌더링 방법과 상호 작용이 발생하는 위치를 결정합니다. 기본값은 정적 SSR이 되었습니다. 즉, 구성 요소가 서버에서 렌더링되고 일반 HTML을 브라우저에 보냅니다. SignalR도 없고 WebAssembly도 없고 빠른 HTML만 있습니다.

.NET 9는 이러한 개념을 다듬고 개발자 환경을 개선하며 성능을 최적화했습니다. .NET 10은 더 나은 재연결 처리, 렌더링 모드 전반의 지속적인 구성 요소 상태, Blazor 스크립트 자체 전달 방식 개선을 통해 이를 더욱 발전시켰습니다.

모든 것을 분석해 봅시다.

.NET 9의 렌더링 모드

최신 Blazor의 핵심은 렌더링 모드의 개념입니다. 알아야 할 네 가지 모드는 다음과 같습니다.

1. 정적 SSR(기본값)

새 Blazor 웹앱을 만들면 구성 요소는 기본적으로 서버에서 정적으로 렌더링됩니다. 서버는 Razor 구성 요소를 처리하고 HTML을 생성하여 브라우저로 보냅니다. 지속적인 연결도 없고 WebAssembly 런타임도 없습니다. 단지 전통적인 요청/응답만 있을 뿐입니다.

이는 콘텐츠가 많은 페이지, 주로 데이터를 표시하는 대시보드 또는 실시간 상호 작용이 필요하지 않은 페이지에 적합합니다.

@page "/products"

<h1>Our Products</h1>

@foreach (var product in products)
{
    <div class="product-card">
        <h3>@product.Name</h3>
        <p>@product.Description</p>
        <span class="price">@product.Price.ToString("C")</span>
    </div>
}

@code {
    private List<Product> products = new();

    protected override async Task OnInitializedAsync()
    {
        products = await ProductService.GetAllAsync();
    }
}

이 구성 요소는 서버에서 렌더링하고 HTML을 생성하며 그게 전부입니다. 진행 중인 연결이 없습니다. 빠른 초기 로드, SEO에 적합, 서버 리소스 사용량 최소화.

2. 대화형 서버버튼 클릭 처리, 사용자 입력 처리, 동적인 UI 업데이트 등 실시간 상호 작용이 필요한 경우 대화형 서버 모드를 선택할 수 있습니다. 그러면 브라우저와 서버 간에 SignalR 연결이 설정되고 해당 연결을 통해 UI 업데이트가 발생합니다.

@page "/counter"
@rendermode InteractiveServer

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

@rendermode InteractiveServer 지시어만 있으면 됩니다. 구성 요소는 처음에 서버에서 렌더링된 다음 후속 상호 작용을 처리하기 위해 SignalR 연결이 설정됩니다. C# 이벤트 핸들러는 서버에서 실행되고 UI 차이점은 브라우저로 전송됩니다.

사용 시기: 상호 작용이 필요할 때 구성 요소는 서버 측 리소스(데이터베이스, API, 파일 시스템)에 액세스해야 하며 WebAssembly가 다운로드될 때까지 기다리지 않고 빠른 초기 로드를 원합니다.

3. 대화형 웹어셈블리

서버 연결을 유지하지 않고 상호 작용을 원하는 경우 Interactive WebAssembly는 .NET WebAssembly 런타임을 사용하여 브라우저에서 직접 구성 요소 논리를 실행합니다.

@page "/search"
@rendermode InteractiveWebAssembly

<h1>Product Search</h1>

<input @bind="searchTerm" @bind:event="oninput" placeholder="Search products..." />

@if (filteredProducts.Any())
{
    <ul>
        @foreach (var product in filteredProducts)
        {
            <li>@product.Name  @product.Price.ToString("C")</li>
        }
    </ul>
}

@code {
    private string searchTerm = string.Empty;
    private List<Product> allProducts = new();
    private IEnumerable<Product> filteredProducts => allProducts
        .Where(p => p.Name.Contains(searchTerm, StringComparison.OrdinalIgnoreCase));

    protected override async Task OnInitializedAsync()
    {
        allProducts = await Http.GetFromJsonAsync<List<Product>>("api/products") ?? new();
    }
}

단점: .NET 런타임 및 어셈블리에 대한 초기 다운로드 비용이 있습니다. 그러나 일단 로드되면 구성 요소는 UI 상호 작용을 위한 서버 왕복 없이 브라우저에서 완전히 실행됩니다.

사용 시기: 대기 시간이 중요한 대화형 구성 요소(예: 서식 있는 텍스트 편집기, 그리기 도구, 실시간 필터링)의 경우, 서버 로드를 줄이려는 경우 또는 프로그레시브 웹 앱(PWA)을 구축할 때.

4. 대화형 자동

이것이 실용적인 중간 지점이자 제가 가장 좋아하는 기능 중 하나입니다. Interactive Auto는 첫 번째 로드를 위해 SignalR을 통한 서버 측 렌더링으로 시작한 다음 백그라운드에서 WebAssembly 런타임을 자동으로 다운로드합니다. 후속 방문에서는 구성 요소가 WebAssembly에서 실행됩니다.

@page "/dashboard"
@rendermode InteractiveAuto

<h1>Dashboard</h1>

<DashboardWidget Title="Sales" Value="@salesTotal" />
<DashboardWidget Title="Users" Value="@activeUsers" />

<button @onclick="RefreshData">Refresh</button>

@code {
    private decimal salesTotal;
    private int activeUsers;

    protected override async Task OnInitializedAsync()
    {
        await RefreshData();
    }

    private async Task RefreshData()
    {
        var data = await DashboardService.GetSummaryAsync();
        salesTotal = data.SalesTotal;
        activeUsers = data.ActiveUsers;
    }
}

이는 빠른 첫 번째 렌더링(WASM 다운로드를 기다리지 않음)과 결국 구성 요소가 클라이언트 측에서 실행된다는 두 가지 장점을 모두 제공합니다. 사용자는 전환을 알아차리지 못합니다.

사용 시기: 빠른 초기 로드와 최종 클라이언트 측 실행을 모두 원하는 경우. 이는 많은 대화형 구성 요소에 대한 훌륭한 기본 선택입니다.

스트리밍 SSR: 양쪽 세계의 최고

스트리밍 SSR은 단순해 보이지만 인지된 성능에 엄청난 차이를 만드는 기능 중 하나입니다. 아이디어는 다음과 같습니다. HTML을 보내기 전에 모든 데이터가 로드될 때까지 기다리는 대신 서버는 페이지 셸을 즉시 보낸 다음 데이터가 사용 가능해지면 콘텐츠 업데이트를 스트림합니다.

@page "/reports"
@attribute [StreamRendering]

<h1>Monthly Reports</h1>

@if (reports is null)
{
    <div class="loading-spinner">
        <p>Loading reports...</p>
    </div>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Month</th>
                <th>Revenue</th>
                <th>Growth</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var report in reports)
            {
                <tr>
                    <td>@report.Month</td>
                    <td>@report.Revenue.ToString("C")</td>
                    <td class="@(report.Growth >= 0 ? "text-success" : "text-danger")">
                        @report.Growth.ToString("P1")
                    </td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private List<MonthlyReport>? reports;

    protected override async Task OnInitializedAsync()
    {
        // This might take a couple of seconds
        reports = await ReportService.GetMonthlyReportsAsync();
    }
}

[StreamRendering] 속성을 사용하면 다음과 같은 일이 발생합니다.

  1. 서버는 로딩 스피너와 함께 HTML을 즉시 보냅니다.
  2. OnInitializedAsync가 실행되어 데이터를 가져옵니다.
  3. 데이터가 도착하면 서버는 업데이트된 HTML(테이블)을 브라우저로 스트리밍합니다.
  4. 브라우저는 전체 페이지를 다시 로드하지 않고도 DOM을 패치합니다.

사용자는 로딩 표시기와 함께 페이지를 즉시 본 다음 콘텐츠가 채워집니다. JavaScript 프레임워크가 필요하지 않습니다. WebSocket 연결이 없습니다. HTTP 스트리밍을 영리하게 사용하는 것뿐입니다.사용 시기: 렌더링 중에 데이터를 가져오는 정적 SSR 페이지. 제품 목록 페이지, 대시보드, 보고서 등 어디에서나 초기 데이터 로드에 수백 밀리초 이상이 걸릴 수 있습니다.

사용하지 말아야 할 경우: 데이터가 매우 빠르게(100ms 미만) 로드되는 경우 스트리밍 오버헤드는 그만한 가치가 없습니다. 또한 스트리밍 SSR은 지속적인 상호작용을 제공하지 않습니다. 이를 위해서는 여전히 대화형 렌더링 모드가 필요합니다.

향상된 탐색 및 양식 처리

최신 Blazor의 미묘하지만 강력한 개선 사항 중 하나는 향상된 탐색 기능입니다. 기본적으로 Blazor는 내부 링크 클릭 및 양식 제출을 가로채서 fetch를 통해 새 페이지 콘텐츠를 가져오고 전체 브라우저 탐색을 수행하는 대신 DOM을 패치합니다.

이는 정적 SSR 페이지 사이를 탐색하는 것이 SPA처럼 느껴진다는 것을 의미합니다. 전체 페이지 플래시가 없고 스크롤 위치가 유지될 수 있으며 경험이 매우 매끄러워집니다.

작동 방식

Blazor 스크립트(blazor.web.js)가 로드되면 내부 링크에 대한 클릭을 자동으로 차단합니다. 기존 브라우저 탐색 대신 다음을 수행합니다.

  1. 대상 URL에 fetch 요청을 보냅니다.
  2. HTML 응답을 받습니다.
  3. 새 콘텐츠를 기존 DOM에 병합합니다.
  4. 브라우저의 URL과 기록을 업데이트합니다.

이 기능을 활성화하기 위해 아무것도 할 필요가 없습니다. 기본적으로 켜져 있습니다. 하지만 다음과 같이 제어할 수 있습니다.

<!-- Disable enhanced navigation for a specific link -->
<a href="/legacy-page" data-enhance-nav="false">Legacy Page</a>

<!-- Force a full page reload for external-like behavior -->
<a href="/downloads/report.pdf" data-enhance-nav="false">Download Report</a>

향상된 양식 처리

양식도 동일한 처리를 받습니다. Blazor의 양식 처리와 함께 EditForm 또는 표준 <form> 요소를 사용하면 제출이 가로채서 fetch를 통해 처리됩니다.

@page "/contact"

<EditForm Model="contactModel" OnValidSubmit="HandleSubmit" FormName="contact" Enhance>
    <DataAnnotationsValidator />

    <div class="mb-3">
        <label for="name">Name</label>
        <InputText id="name" @bind-Value="contactModel.Name" class="form-control" />
        <ValidationMessage For="() => contactModel.Name" />
    </div>

    <div class="mb-3">
        <label for="email">Email</label>
        <InputText id="email" @bind-Value="contactModel.Email" class="form-control" />
        <ValidationMessage For="() => contactModel.Email" />
    </div>

    <div class="mb-3">
        <label for="message">Message</label>
        <InputTextArea id="message" @bind-Value="contactModel.Message" class="form-control" />
        <ValidationMessage For="() => contactModel.Message" />
    </div>

    <button type="submit" class="btn btn-primary">Send</button>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private ContactModel contactModel { get; set; } = new();

    private async Task HandleSubmit()
    {
        await ContactService.SubmitAsync(contactModel);
        contactModel = new ContactModel();
    }
}

EditFormEnhance 속성은 Blazor에게 양식 제출을 가로채도록 지시합니다. 양식이 서버에 게시되고, 서버가 이를 처리하고 페이지를 다시 렌더링하며, 업데이트된 HTML이 다시 스트리밍됩니다. 이 모든 작업은 전체 페이지 탐색 없이 수행됩니다. 대화식으로 느껴지지만 완전히 서버에서 렌더링됩니다.

[SupplyParameterFromForm] 속성에 주목하세요. 이는 Blazor가 정적 SSR 시나리오에서 게시된 양식 데이터를 모델에 바인딩하는 방법입니다. 이는 전통적인 양식 게시물과 Blazor의 구성 요소 모델 사이를 연결하는 다리입니다.

페이지별 및 구성 요소별 상호 작용

새 모델의 가장 강력한 측면 중 하나는 단일 애플리케이션 내에서 렌더링 모드를 혼합할 수 있다는 것입니다. 제품 목록 페이지는 정적 SSR일 수 있고, 장바구니는 Interactive Server일 수 있으며, 제품 구성기는 Interactive WebAssembly일 수 있습니다. 이 모든 것이 동일한 앱에 있습니다.

구성 요소 수준에서 렌더링 모드 설정

@rendermode 지시문을 사용하여 구성 요소에서 직접 렌더링 모드를 설정할 수 있습니다.

@* This component is interactive via Server *@
@rendermode InteractiveServer

<h3>Live Chat</h3>
<!-- chat UI here -->

또는 상위 구성 요소를 사용할 때 설정할 수 있습니다.

@page "/product/{Id:int}"

<h1>@product?.Name</h1>
<p>@product?.Description</p>

<!-- This child component gets its own interactive render mode -->
<ProductConfigurator Product="product" @rendermode="InteractiveWebAssembly" />

<!-- This stays static -->
<ProductReviews ProductId="Id" />

@code {
    [Parameter] public int Id { get; set; }
    private Product? product;

    protected override async Task OnInitializedAsync()
    {
        product = await ProductService.GetByIdAsync(Id);
    }
}

이 예에서 페이지 자체는 정적 SSR입니다. ProductConfigurator 구성 요소는 풍부한 클라이언트 측 상호 작용을 위해 WebAssembly에서 실행됩니다. ProductReviews 구성 요소는 단지 데이터만 표시하기 때문에 정적으로 유지됩니다.

렌더링 모드를 전역적으로 설정하기

기본적으로 모든 페이지를 대화형으로 만들려면 App.razor의 루트 수준에서 렌더링 모드를 설정할 수 있습니다.

<Routes @rendermode="InteractiveServer" />
```이는 서버 렌더링을 통해 모든 페이지를 대화형으로 만듭니다. 필요한 경우 개별 구성 요소가 이를 재정의할  있습니다.

### 기억해야 할 중요한 규칙

렌더링 모드를 혼합할  염두에 두어야   가지 제약 조건이 있습니다.

- **하위 구성 요소는 상위 구성 요소보다 "더 대화형" 렌더링 모드를 가질  없습니다.** 상위 구성 요소가 정적이면 하위 구성 요소는 정적이거나 대화형일  있습니다. 그러나 부모가 Interactive Server인 경우 자식은 Interactive WebAssembly가   없습니다(Server 또는 Auto여야 ).
- **대화형 구성 요소는 정적 부모의 범위 서비스를 직접 사용할  없습니다.** 구성 요소가 WebAssembly에서 실행되는 경우 서버  `DbContext` 인스턴스에 직접 액세스할  없습니다. API 계층이 필요합니다.
- **상태는 렌더링 모드 간에 자동으로 전송되지 않습니다.** 구성 요소가 서버에서 사전 렌더링된 다음 WebAssembly로 전환하는 경우 상태 지속성을 명시적으로 처리해야 합니다. 이에 대한 자세한 내용은 .NET 10 섹션에서 확인하세요.

## .NET 10의 새로운 기능

.NET 10 안정성과 개발자 경험에 초점을 맞춰 점진적인 개선 접근 방식을 이어갑니다. Blazor 상호 작용의 주요 내용은 다음과 같습니다.

### 향상된 재연결 경험

프로덕션에서 대화형 서버 모드를 사용한 경우 아마도 재연결 오버레이를 접했을 것입니다. , SignalR 연결이 끊어지고 사용자에게 "재연결 중..." 메시지가 표시되는 순간입니다. .NET 10에서는  환경이 훨씬  좋아졌습니다.

이제 재연결 논리가 재시도에 대해  똑똑해졌습니다. 고정된 재시도 간격 대신 상황에 맞는 백오프 전략을 사용합니다. 다시 연결하는 동안의 UI도 더욱 세련되었으며 경험을 사용자 정의할  있는  나은 후크가 있습니다.

```razor
<!-- In your App.razor or layout -->
<div id="components-reconnect-modal">
    <div class="reconnect-visible">
        <p>Connection lost. Attempting to reconnect...</p>
        <div class="spinner"></div>
    </div>
    <div class="reconnect-failed">
        <p>Could not reconnect to the server.</p>
        <button onclick="location.reload()">Reload</button>
    </div>
    <div class="reconnect-rejected">
        <p>Your session has expired.</p>
        <a href="/">Return to Home</a>
    </div>
</div>

이제 프레임워크는 일시적인 오류가 발생할 경우 더욱 적극적으로 재연결을 시도하며 회로 상태를 보다 안정적으로 복원할 수 있습니다. 이는 사용자의 “페이지를 다시 로드하세요"라는 순간이 줄어든다는 것을 의미합니다.

렌더링 모드 전반에 걸쳐 지속적인 구성 요소 상태

이것은 큰 것입니다. .NET 9에서는 구성 요소가 서버에서 사전 렌더링된 다음 WebAssembly로 전환되거나 렌더링 모드 간에 전환되면 구성 요소 상태가 손실됩니다. 구성요소가 효과적으로 다시 초기화되므로 데이터 가져오기가 중복되고 UI가 깜박일 수 있습니다.

.NET 10은 렌더링 모드 전환 전반에 걸쳐 보다 원활하게 작동하도록 PersistentComponentState 서비스를 개선합니다.

@page "/weather"
@rendermode InteractiveWebAssembly
@inject PersistentComponentState ApplicationState

<h1>Weather Forecast</h1>

@if (forecasts is null)
{
    <p>Loading...</p>
}
else
{
    @foreach (var forecast in forecasts)
    {
        <div class="forecast-card">
            <h4>@forecast.Date.ToShortDateString()</h4>
            <p>@forecast.Summary  @forecast.TemperatureC°C</p>
        </div>
    }
}

@code {
    private List<WeatherForecast>? forecasts;
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        persistingSubscription = ApplicationState.RegisterOnPersisting(PersistData);

        if (!ApplicationState.TryTakeFromJson<List<WeatherForecast>>(
            "weather-forecasts", out var restored))
        {
            // Data wasn't persisted from prerendering — fetch it
            forecasts = await Http.GetFromJsonAsync<List<WeatherForecast>>("api/weather");
        }
        else
        {
            forecasts = restored;
        }
    }

    private Task PersistData()
    {
        ApplicationState.PersistAsJson("weather-forecasts", forecasts);
        return Task.CompletedTask;
    }

    public void Dispose()
    {
        persistingSubscription.Dispose();
    }
}

.NET 10의 개선 사항을 통해 이 패턴은 더욱 안정적으로 작동합니다. 사전 렌더링 중에 직렬화된 상태는 구성 요소가 대화형 모드에서 초기화될 때 적절하게 사용할 수 있으므로 이중 데이터 가져오기 및 사용자에게 표시될 수 있는 짧은 깜박임이 방지됩니다.

정적 웹 자산으로서의 Blazor 스크립트

이전 버전에서는 Blazor JavaScript 파일(blazor.web.js)이 프레임워크의 내부 엔드포인트에서 제공되었습니다. .NET 10에서는 정적 웹 자산으로 제공됩니다. 이는 작은 변화처럼 들릴 수도 있지만 실질적인 이점이 있습니다.- 더 나은 캐싱: 정적 웹 자산은 적절한 캐시 헤더와 지문 URL을 가져오므로 브라우저는 이를 더욱 효과적으로 캐시합니다.

  • CDN 친화적: 일반 정적 파일이므로 CDN은 이를 엣지 위치에서 캐시하고 제공할 수 있습니다.
  • 압축: 정적 웹 자산 압축이 자동으로 적용되어 전송 중인 스크립트 크기가 줄어듭니다.

참조 방법을 변경할 필요가 없습니다. 프레임워크가 업데이트된 경로를 자동으로 처리합니다.

모범 사례: 올바른 렌더링 모드 선택

여러 프로젝트에 걸쳐 이러한 모든 모드를 사용한 후의 결정 프레임워크는 다음과 같습니다.

정적 SSR로 시작

정적 SSR을 기본값으로 설정하세요. 대부분의 애플리케이션에서 대부분의 페이지는 주로 데이터 표시에 관한 것입니다. 제품 페이지, 블로그 게시물, 사용자 프로필, 설정 페이지 등에는 실시간 상호 작용이 필요하지 않습니다. 정적 SSR은 최고의 성능, 가장 낮은 리소스 사용량 및 가장 단순한 정신 모델을 제공합니다.

필요한 경우에만 상호작용 기능 추가

사용자 상호 작용에 실시간으로 응답해야 하는 특정 구성 요소를 식별합니다. ‘좋아요’ 버튼, 채팅 위젯, 드래그 앤 드롭 인터페이스 등에는 상호작용이 필요합니다. 그러나 그들을 둘러싼 페이지는 아마도 그렇지 않을 것입니다.

대화형 자동 모드를 대화형 모드로 사용하세요

대화형 기능이 필요한 경우 Interactive Auto가 기본적으로 최선의 선택인 경우가 많습니다. 최종 클라이언트 측 실행(WebAssembly)을 통해 빠른 초기 로드(서버 렌더링)를 제공합니다. 사용자는 두 가지 장점을 최대한 활용하고 코드를 한 번만 작성하면 됩니다.

특정 사례를 위한 대화형 서버 예약

다음과 같은 경우 대화형 서버를 사용하세요.

  • 구성 요소는 서버 리소스(데이터베이스, 파일 시스템, 내부 API)에 직접 액세스해야 합니다.
  • WebAssembly 다운로드 크기가 문제로 Auto를 사용할 수 없습니다.
  • 보안상의 이유로(예: 민감한 데이터 처리) 구성 요소가 항상 서버에서 실행되어야 합니다.

스트리밍 SSR을 아낌없이 사용하세요

정적 SSR 페이지가 데이터를 가져오는 경우 [StreamRendering]를 추가하세요. 비용은 최소화되며 인지된 성능 향상은 상당합니다. 사용자는 빈 페이지를 쳐다보는 것이 아니라 점진적으로 나타나는 콘텐츠를 봅니다.

상태 전환을 신중하게 처리

Interactive Auto를 사용하거나 WebAssembly와 사전 렌더링을 혼합하는 경우 중복된 데이터 가져오기를 방지하려면 항상 PersistentComponentState를 사용하세요. 사용자는 깜박이는 콘텐츠가 없다는 점에 감사할 것입니다.

구성요소 트리를 염두에 두세요

렌더링 모드 계층 구조 규칙을 기억하세요. 대화형 경계가 이해되도록 구성 요소 트리를 계획합니다. 일반적인 패턴은 필요한 곳에 대화형 “섬"이 포함된 정적 레이아웃을 갖는 것입니다.

@* Layout: Static SSR *@
<header>
    <NavMenu />
    <UserMenu @rendermode="InteractiveServer" /> @* Needs real-time auth state *@
</header>

<main>
    @Body
</main>

<footer>
    <ChatWidget @rendermode="InteractiveAuto" /> @* Rich interactivity *@
</footer>

결론

.NET 9 및 .NET 10의 Blazor 상호 작용 모델은 웹 애플리케이션 구축에 대한 성숙하고 신중한 접근 방식을 나타냅니다. 구성 요소별로 렌더링 모드를 선택할 수 있는 기능, 원활하게 향상된 탐색, 스트리밍 SSR, 재연결 및 상태 관리의 지속적인 개선으로 인해 광범위한 애플리케이션에 대한 강력한 선택이 됩니다.핵심 통찰력은 상호작용은 이분법적인 선택이 아니라 스펙트럼입니다라는 것입니다. 대부분의 애플리케이션은 정적일 수 있습니다. 일부 부품에는 서버 기반 상호 작용이 필요합니다. 일부는 브라우저에서 실행하면 이점을 얻을 수 있습니다. 이제 Blazor를 사용하면 프레임워크와 싸우지 않고도 가장 세밀한 수준(개별 구성 요소)에서 선택할 수 있습니다.

새 프로젝트를 시작하는 경우 제 조언은 간단합니다. Blazor 웹 앱을 만들고, 정적 SSR로 시작하고, 데이터가 많은 페이지에 [StreamRendering]를 추가하고, 필요할 때만 개별 구성 요소를 대화형 모드로 승격하세요. 빠르고 효율적이며 확장성이 뛰어난 애플리케이션을 얻게 될 것입니다.

즐거운 코딩 되시기 바랍니다. 언제나 그렇듯이 궁금한 점이 있으면 언제든지 문의해 주세요!