'How can I save a Blazor Component instance in a variable and render it in my .cshtml

Considering I have a class called Tab.

public class Tab
{
    public Guid Id { get; }
    public bool IsVisible { get; set; }

    protected Tab()
    {
        Id = Guid.NewGuid();
    }
}

I want to strictly couple these tabs to a Blazor Component instance and render those instances by iterating over the tabs. I want to have control over when a Component is created and when it is destroyed again.

I want to do this because that way I can persist the state for each component.

Here is the problem with the easy approach. Considering something like this:

@code {
    public void CreateNewTabAndRemoveOldTab()
    {
        Tabs.RemoveAt(0);
        Tabs.Add(new Tab());
    }
}

foreach (var tab in Tabs)
{
    <MyTabComponent/>
}

The newly created tab will simply take over the state of the removed tab. OnInitialized will not be called.

I have looked into RenderFragment, but it does not look like its working property. The problem is that the Blazor Framework will still decide when a new component is created (thus calling OnInitialized) or when existing instance are used.



Solution 1:[1]

If I read this correctly, Tab is a class, not a component. You need to decouple your list of Tabs from the component that renders them. Your list of tabs lives in a service, the scope depends on what you're doing with them. Your Tab Component displays the currently selected Tab in the list. If you show a little more of your logic I can probably show you a relevant working example.

Solution 2:[2]

Check this

@ref it's reference to your component it's added to list of components.

@implements IDisposable

@foreach (var tab in tabs)
{
    <MyTabComponent @ref=@TabRef Tab=@tab />
}

@code {

    List<Tab> tabs = new List<Tab>();
    List<MyTabComponent> tabsComp = new List<MyTabComponent>();

    MyTabComponent TabRef {
        set { tabsComp.Add(value); }
    }

    public void CreateNewTabAndRemoveOldTab()
    {
        tabs.RemoveAt(0);
        tabs.Add(new Tab());
    }
    
    public void Dispose()
    {
    }
}

Solution 3:[3]

MyTabs.razor

       <CascadingValue Value="@this" IsFixed="true">
        foreach (var tab in Tabs)
        {
            <MyTabComponent/>
        }
        </CascadingValue>
    
    @code{
    private List<MyTabComponent> Tabs;
    
    public void Register(MyTabComponent tab)
            {
                this.Tabs.Add(tab);
    }
    
    public void UnRegister(MyTabComponent tab)
            {
                this.Tabs.Remove(tab);
    }
    }

MyTabComponent.razor

@implements IDisposable
<div></div>

@code{
[CascadingParameter]
protected MyTabs Context { get; set; }

protected override void OnInitialized()
        {
            Context?.Register(this);
//  implement your logic here
        }

public void Dispose()
        {
            Context?.UnRegister(this);
//  implement your logic here
        }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MrC aka Shaun Curtis
Solution 2 user3529134
Solution 3 Dharman