How to run code after Blazor component has rendered
Tags: dotnet, aspnet, blazor
Published: 2020-08-31 16:06:51

---
title: How to run code after Blazor component has rendered
published: true
date: 2020-08-17 00:00:00 UTC
tags: dotnet, aspnet, blazor
cover_image: https://swimburger.net/media/fmqpu0qi/blazor-social.png?anchor=center&mode=crop&width=1000&height=420&rnd=132421552520100000
canonical_url: https://swimburger.net/blog/dotnet/how-to-run-code-after-blazor-component-has-rendered
---

Blazor components render their template whenever state has changed and sometimes you need to invoke some code after rendering has completed. This blog post will show you how to run code after your Blazor component has rendered, on every render or as needed.

## Sample starting point

ASP.NET Blazor will re-render your razor template whenever databound data has changed. For example, a list of strings could be iterated over and printed as paragraphs:

```
@inject IJSRuntime JSRuntime
<button type="button" @onclick="GenerateMoreLoremIpsum">Generate more Lorem Ipsum</button>
@foreach (var paragraph in loremParagraphs)
{
    <p>@paragraph</p>
}

@code {
    private List<string> loremParagraphs = new List<string>();

    protected override Task OnInitializedAsync()
    {
        for (int i = 0; i < 8; i++)
        {
            loremParagraphs.Add(GetRandomLoremParagraph());
        }
        return base.OnInitializedAsync();
    }

    private void GenerateMoreLoremIpsum()
    {
        loremParagraphs.Add(GetRandomLoremParagraph());
    }

    // implementation details ommitted, for full source see https://github.com/Swimburger/Blazor-AfterRenderExecution/blob/master/App.razor
}
```

When the 'Generate more Lorem Ipsum' button is clicked, the `GenerateMoreLoremIpsum` method is invoked and a new string is added to the `loremParagraphs` list. Blazor will pick up on this state change and re-render the template which will add a new paragraph-element.

## Run code every time a component has been rendered

From time to time, you will need to perform some action after the template has been rendered or re-rendered. For this you can override the `OnAfterRenderAsync` or `OnAfterRender` method.  
In this demo, whenever a new paragraph is rendered, the browser should scroll to it:

```
@inject IJSRuntime JSRuntime
<button type="button" @onclick="GenerateMoreLoremIpsum">Generate more Lorem Ipsum</button>
@foreach (var paragraph in loremParagraphs)
{
    <p>@paragraph</p>
}

@code {
    private List<string> loremParagraphs = new List<string>();

    protected override Task OnInitializedAsync()
    {
        for (int i = 0; i < 8; i++)
        {
            loremParagraphs.Add(GetRandomLoremParagraph());
        }
        return base.OnInitializedAsync();
    }

    protected override Task OnAfterRenderAsync(bool firstRender)
    {
        JSRuntime.InvokeVoidAsync("scrollToParagraph", loremParagraphs.Count - 1);
        return base.OnAfterRenderAsync(firstRender);
    }

    private void GenerateMoreLoremIpsum()
    {
        loremParagraphs.Add(GetRandomLoremParagraph());
    }

    // implementation details ommitted, for full source see https://github.com/Swimburger/Blazor-AfterRenderExecution/blob/master/App.razor
}
```

Using `JSRuntime.InvokeVoidAsync` the Blazor component calls a JavaScript function `scrollToParagraph` passing in the index of the last paragraph. Here is the source of `scrollToParagraph` which is in the index.html file.

```
window.scrollToParagraph = function (paragraphIndex) {
    var element = document.querySelector('p:nth-child(' + (paragraphIndex + 1) + ')');
    window.scrollTo(0, element.offsetTop);
}
```

This fulfills the scrolling requirement, but the scrolling will occur every time the template is re-rendered, even when the re-render is not triggered by new paragraphs being added. This is undesirable and won't scale well to larger applications.

## Run code as needed after component has been rendered

Instead of putting the logic directly inside the `OnAfterRenderAsync` callback, you can introduce a list of actions to invoke after rendering. Whenever code needs to be invoked after rendering, you can push a new Action into the list:

```
@code {
    // implementation details ommitted, for full source see https://github.com/Swimburger/Blazor-AfterRenderExecution/blob/master/App.razor

    // store all the actions you want to run **once** after rendering
    private List<Action> actionsToRunAfterRender = new List<Action>();

    protected override Task OnAfterRenderAsync(bool firstRender)
    {
        // run all the actions (.NET code) **once** after rendering
        foreach (var actionToRun in actionsToRunAfterRender)
        {
            actionToRun();
        }
        // clear the actions to make sure the actions only run **once**
        actionsToRunAfterRender.Clear();
        return base.OnAfterRenderAsync(firstRender);
    }

    private void GenerateMoreLoremIpsum()
    {
        loremParagraphs.Add(GetRandomLoremParagraph());
        // pass action to actionsToRunAfterRender to run the scrollToParagraph code **once** after the new paragraph is rendered
        actionsToRunAfterRender.Add(() => JSRuntime.InvokeVoidAsync("scrollToParagraph", loremParagraphs.Count - 1));
    }

    // implementation details ommitted, for full source see https://github.com/Swimburger/Blazor-AfterRenderExecution/blob/master/App.razor
}
```

Now all actions from the `actionsToRunAfterRender`-list will be invoked once in the `OnAfterRenderAsync` callback and then the list is emptied. The scroll logic is now pushed into the `actionsToRunAfterRender`-list from the `GenerateMoreLoremIpsum` method, meaning scrolling will only occur after the button is clicked. Other irrelevant state changes causing re-rendering won't trigger scrolling anymore.

## Extract logic into a reusable base Blazor component

Instead of having this after render logic be in every component you need, you can create a reusable base component by inheriting from `ComponentBase`:

```
public class MyComponentBase : ComponentBase
{
    // store all the actions you want to run **once** after rendering
    private List<Action> actionsToRunAfterRender = new List<Action>();
    protected override Task OnAfterRenderAsync(bool firstRender)
    {
        // run all the actions (.NET code) **once** after rendering
        foreach (var actionToRun in actionsToRunAfterRender)
        {
            actionToRun();
        }
        // clear the actions to make sure the actions only run **once**
        actionsToRunAfterRender.Clear();
        return base.OnAfterRenderAsync(firstRender);
    }

    /// <summary>
    /// Run an action once after the component is rendered
    /// </summary>
    /// <param name="action">Action to invoke after render</param>
    protected void RunAfterRender(Action action) => actionsToRunAfterRender.Add(action);
}
```

Now all the AfterRender related code can be removed from the components, and you can use `RunAfterRender` instead:

```
RunAfterRender(() => JSRuntime.InvokeVoidAsync("scrollToParagraph", loremParagraphs.Count - 1));
```

## Conclusion

Blazor components render their template whenever state has changed and sometimes you need to invoke some code after rendering has completed. You can override the `OnAfterRenderAsync` or `OnAfterRender` method to run code when rendering of the component has completed.  
Though, you may not want to run code every time the component has rendered. By storing a list of actions, you can invoke code as needed in the `OnAfterRenderAsync` callback.

See this [demo in action here](https://swimburger.github.io/Blazor-AfterRenderExecution/) and you can find [the source code on GitHub here](https://github.com/Swimburger/Blazor-AfterRenderExecution).