Search code examples
c#asp.net-coreblazorblazor-webassembly

What are blazor RootComponents?


The blazor template has this:

builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

I know what App and HeadOutlet are (they are covered in the docs).

What are RootComponents generally?

Can I add my own components too? (What sort of components might those be?)


Solution

  • What are RootComponents generally?

    The Renderer needs a starting node for a RenderTree. That's the root component. A WASM application can have one or more. It's probably easier to demonstrate that describe.

    Create a project from the WebAssembly template.

    Here's a modified index.html. Notice the extra html Div and Span elements.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
        <title>BlazorApp1</title>
        <base href="/" />
        <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
        <link href="css/app.css" rel="stylesheet" />
        <link href="BlazorApp1.styles.css" rel="stylesheet" />
    </head>
    
    <body>
        <div id="counter"></div>
    
        <span id="useless"></span>
    
        <div id="app">Loading...</div>
    
        <div id="blazor-error-ui">
            An unhandled error has occurred.
            <a href="" class="reload">Reload</a>
            <a class="dismiss">🗙</a>
        </div>
        <script src="_framework/blazor.webassembly.js"></script>
    </body>
    
    </html>
    

    Run that and nothing is different.

    Now modify Program to tell the Application to map Counter to the html element with the appropriate id:

    using BlazorApp1;
    using BlazorApp1.Pages;
    using Microsoft.AspNetCore.Components.Web;
    using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
    
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    builder.RootComponents.Add<App>("#app");
    builder.RootComponents.Add<HeadOutlet>("head::after");
    builder.RootComponents.Add<Counter>("#counter");
    
    builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
    
    await builder.Build().RunAsync();
    

    You now have three RenderTree's.

    Can I add my own components too? (What sort of components might those be?)

    Any class that implements IComponent can be a root component.

    Here's a demo:

    public class TotallyUselessComponent : IComponent
    {
        private RenderHandle _renderHandle;
        public void Attach(RenderHandle renderHandle)
            => _renderHandle = renderHandle;
    
        public Task SetParametersAsync(ParameterView parameters)
        {
            _renderHandle.Render((builder) =>
                {
                    builder.AddMarkupContent(0, $"<div class='alert alert-danger m-3'>I'm here but I'm totally Useless.</div>");
                }
            );
    
            return Task.CompletedTask;
        }
    }
    

    And Update Program

    builder.RootComponents.Add<App>("#app");
    builder.RootComponents.Add<HeadOutlet>("head::after");
    builder.RootComponents.Add<Counter>("#counter");
    builder.RootComponents.Add<TotallyUselessComponent>("#useless");
    

    Screen shot of what you get.

    enter image description here