Search code examples
blazorrenderingrerender

Blazor: StateHasChanged could be called in parent or if called in Child has better performance?


My question is regarding StateHasChanged:

I have this code in Parent:

    [Inject]
    private IProjectActionsService ProjectActionsService { get; set; }
    private ProjectModel Project { get; set; }
    
    protected override void OnInitialized()        
    {                                 
        ProjectActionsService.FavouritesOnChange += FavouriteTasksChanged;

        await GetProjectData(Project);
    }

    private void FavouriteTasksChanged(TreeItemModel treeItem)
    {
        var remove = treeItem.Hidden;

        Project.TreeDataDict.TryGetValue(treeItem.NodeId, out treeItem);

        if (remove)
        {
            Project.TreeDataSource[0].Children.Remove(treeItem);
        }
        else
        {
            Project.TreeDataSource[0].Children.Add(treeItem);
        }

        StateHasChanged();
    }

this rerenders the child which show the favourites to the user

Here is Child:

    [Parameter]
    public ProjectModel Project { get; set; }

My question is if instead calling StateHasChanged in Parent, I could do the following to child:

    [Parameter]
    public ProjectModel Project { get; set; }

    protected override void OnInitialized()        
    {                                 
        ProjectActionsService.FavouritesOnChange += FavouriteTasksChanged;
    }

    private void FavouriteTasksChanged(TreeItemModel treeItem)
    {
        var remove = treeItem.Hidden;

        Project.TreeDataDict.TryGetValue(treeItem.NodeId, out treeItem);

        if (remove)
        {
            Project.TreeDataSource[0].Children.Remove(treeItem);
        }
        else
        {
            Project.TreeDataSource[0].Children.Add(treeItem);
        }

        StateHasChanged();
    }

And call StatesHasChanged on child.

Will this have any impact on performance (ex: not making parent rerender) or will do exactly the same (ex: just render where is being shown to the user which happens only in the child) ??

Update starts Here:

So I did some tests and for fact using StatHasChanged in Parent will call OnAfterRender of every child Component. By running in the child it only runs its own OnAfterRender.

Best Regards


Solution

  • Will this have any impact on performance (ex: not making parent rerender)

    Yes. Call StateHasChanged for the smallest scope necessary.
    Assuming the Tree is rendered in the Child Component.

    what I have read tells me that only the changed properties will be rendered

    That is correct but first the 'diffing engine' has to run, taking time. And that engine errs on the safe side: any Component with a mutable object as parameter will be re-rendered.

    From the Blazor performance page:

    1. After a new set of parameter values is received, each component decides whether to rerender. By default, components rerender if the parameter values may have changed, for example, if they're mutable objects.

    On a side note, what is the lifetime (scope) of the ProjectActionsService? I think you had better have @implement IDisposable and use that to unsubscribe (-=) your eventhandlers.