static void

Blazor Components

Each .razor file (+ partial classes) is a component- and invisibly inherits ComponentBase : IComponent. You can @inherits from another base class than inherits from ComponentBase.

Layouts inherit LayoutComponentBase and have a @Body parameter. Apply a layout with @layout name (overrides router's RouteView DefaultLayout). A folder with an _imports.razor can have a @layout that applies to all components in the folder.

You can also @implements IDisposable or @implements IAsyncDisposable (but not both!) - things like events and js interop.

Prefer using .razor.cs partial classes for code alongside the .razor, avoid @code blocks. NB: @using and using statements are different.

You can also use standard generic C# instead of @typeparam TMyType

@code {
    //don't do this, this is a partial class, so add x.razor.cs
    [Parameter]
    public string? Name { getset; }
}
using Microsoft.AspNetCore.Components;

namespace BlazorApp.Client.Shared;

//better: partial class with your code separate from markup
public partial class UserName
{
    [Parameter]
    public string? Name { getset; }
}

You can use an ILogger, but in WASM it is just to browser devtools/F12. There is no Application Insights for blazor client side. Finding client side exceptions is tough, but perhaps a component with an httpClient to send the stack to the server might help...

Lifecycle

This component shows a list of the lifecycle events- SetParametersAsync, OnInitialized and OnParametersSet.
OnAfterRender should not appear (because it finished rendering!) unless we notify that StateHasChanged() as done here!

@inject ILogger<UserNameLogger
<ul>
    @foreach (var e in LifeCycleEvents)
    {
        <li>@e</li>
    }
</ul>

@code {

    public IList<string> LifeCycleEvents { getset; } = new List<string>();

    //lifecycle in order

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        //sets the parameters
        await base.SetParametersAsync(parameters);
        LifeCycleEvents.Add("SetParametersAsync");
    }

    protected override void OnInitialized()
    {
        //this (or the async version) is the OnLoad for most startup logic
        LifeCycleEvents.Add("OnInitialized");
    }
    //or async version
    // protected override async Task OnInitializedAsync()
    // {
    //     await ...
    // }
    protected override void OnParametersSet()
    {
        LifeCycleEvents.Add("OnParametersSet");
    }

    protected override void OnAfterRender(bool firstRender)
    {
        LifeCycleEvents.Add("OnAfterRender " + firstRender);
        Logger.LogInformation("Too late, already rendered, but this appears in F12 devtools");
        //you can make it appear by changing state
        if (firstRenderStateHasChanged();
    }
}

Each component (including eg form components like InputText) can have a @ref- you use this as the id.