stonith404
stonith404

Reputation: 530

Preventing double rendering with the combination of "Interactive Server Render Mode" and "Stream Rendering"

I'm exploring the new Blazor features of .NET 8 and I'm encountering an issue where my component seems to be rendering twice. The issue occurs when I'm using "Stream Rendering" combined with the "Interactive Server Render Mode".

I've simplified my code for clarity:

@attribute [StreamRendering]
@rendermode InteractiveServer

@if (data == null)
{
    <p>Loading...</p>
}
else
{
    <p>@data</p>
}

@code {
   private string? data;

    protected override async Task OnInitializedAsync()
    {
        await Task.Delay(1000);
        data = "Hello World!";
    }
}

In this code, I expect the "Loading..." text to be displayed initially, and then, after a delay, the text "Hello World!" should replace it. This works, but as soon as the data gets shown, the component rerenders and the loading text gets shown again.

My questions are:

Upvotes: 6

Views: 5084

Answers (4)

Firewizz
Firewizz

Reputation: 813

I had the same thing, i "solved it" by not using the [Streamrendering] when using interactive server and loading my data like this:

@code 
{
   private string? data;

    protected override async Task OnInitializedAsync()
    {
        _ = Init();
    }
    
    private async Task Init(){
        await Task.Delay(1000);
        data = "Hello World!";
    }

}

This runs the init in another thread. It sends the html to the client. and the other thread updates the data using the interactive server mode. 2 notes:

  • Watch out with doing this multiple times, especially with DbContexts;
  • Do everything that takes time in that init method or that thread so it does not hold up the page.

Don't know if this is the most preferred way but works for me.

Upvotes: 0

Brian Parker
Brian Parker

Reputation: 14613

You can prevent the first render or tell the render engine not to clear the initial data with data-permanent attribute on the element containing the data, this will give the perception of not being rendered twice. Docs

All interactive modes render on the server first, the client is sent html. This normally is a good thing the client sees updates almost instantly. To prevent the "Pre Render" use the prerender parameter on the constructor.

CustomRenderModes.cs

public static class CustomRenderModes
{
    public static readonly InteractiveAutoRenderMode InteractiveAutoRenderModeNoPreRender
        = new InteractiveAutoRenderMode(prerender: false);
    public static readonly InteractiveServerRenderMode InteractiveServerRenderModeNoPreRender
        = new InteractiveServerRenderMode(prerender: false);
    public static readonly InteractiveWebAssemblyRenderMode InteractiveWebAssemblyRenderModeNoPreRender
        = new InteractiveWebAssemblyRenderMode(prerender: false);
}

_imports.razor

@using static {NamespaceOfStaticModelHere}.CustomRenderModes

You can use @(new InteractiveWebAssemblyRenderMode(prerender: false)) directly on your component. The method I have shown with the static class is the same as how MS setup the initial 3 rendermodes with prerender. Source

SomeComponent.razor

@page "/thread/{ThreadId}"
@attribute [Authorize]
@rendermode InteractiveWebAssemblyRenderModeNoPreRender

Docs

Upvotes: 6

alex
alex

Reputation: 61

@attribute [StreamRendering]
@rendermode @(new InteractiveServerRenderMode(prerender: false))

Upvotes: 5

Rob Vettor
Rob Vettor

Reputation: 241

Ran into same behavior where a Blazor 8 WASM component set to @rendermode InteractiveAuto renders twice on every state refresh. I was able to streamline the behavior to rendering just once by changing "@rendermode InteractiveAuto" to @rendermode @(new InteractiveAutoRenderMode(prerender: false)) at the top of the component. You can refer to the documentation from Microsoft.

Still researching the exact tradeoffs of adding that change, but it does work.

Upvotes: 0

Related Questions