jonasmaturana
jonasmaturana

Reputation: 287

How to update two parameters of a Blazor component atomically

I'm creating a component Foo that takes two parameters. I want to bind two variables like this:

<Foo SelectedPage="@SelectedPage" SelectedPageElement="@SelectedPageElement" />

How can I make sure I update both SelectedPage and SelectedPageElement at the same time and only have Foo rerender after both variables are updated?

I want to be able to do something like

SelectedPage = nextPage;
SelectedPageElement = null

without rendering the component twice.

Upvotes: 0

Views: 587

Answers (3)

Michael
Michael

Reputation: 396

You could make a

public record Selection(string SelectedPage, string SelectedPageElement)

and instead of two [Parameter] make the [Parameter] be an instance of the record.

Upvotes: 0

MrC aka Shaun Curtis
MrC aka Shaun Curtis

Reputation: 30016

There are various events that cause a re-render, Foo doesn't render just because you set SelectedPage = nextPage;. It all depends on the context in which you are running those two lines of code.

The following code demonstrates a normal event driven example and shows the number of render events that occur.

Foo

<h3>Foo rendered @renders</h3>

@code {
    [Parameter] public string? SelectedPage { get; set; }
    [Parameter] public string? SelectedPageElement { get; set; }

    // set to 1 as ShouldRender is not called on the first render event
    private int renders = 1;

    protected override bool ShouldRender()
    {
        renders++;
        return true;
    }
}

Demo page

@page "/"

<h1>Hello</h1>

<Foo SelectedPage="@this.selectedPage" SelectedPageElement="@this.selectedPageElement" />
<div>
    <button class="btn btn-primary" @onclick=this.OnClick>Update</button>
</div>

@code
{
    private string? selectedPage;
    private string? selectedPageElement;

    private void OnClick()
    {
        selectedPage = "Hello";
        selectedPageElement = "Me";
    }
}

As you can see there's only one render event associated with the button click. You don't need to write extra code.

Upvotes: 2

Astrid E.
Astrid E.

Reputation: 2872

You can prevent unnecessary rerendering by overriding ComponentBase.ShouldRender().

An example, using simple data types for the component parameters:

  • You can create a private field for each of the parameters. The private fields are populated at component initialization and are then used to keep track of the latest updated value set (i.e. the latest state in which both parameters were updated).
  • Then, by overriding ShouldRender(), you can make sure that both of the parameters actually have an updated value before you allow rerendering to happen.

The code for Foo may look something like:

[Parameter]
public int SelectedPage { get; set; }

[Parameter]
public int SelectedPageElement { get; set; }

private int _selectedPage;
private int _selectedPageElement;

protected override void OnInitialized()
{
    _selectedPage = SelectedPage;
    _selectedPageElement = SelectedPageElement;
}

protected override bool ShouldRender()
{
    if (SelectedPage == _selectedPage)
    {
        return false;
    }
    if (SelectedPageElement == _selectedPageElement)
    {
        return false;
    }

    // Both parameters were updated --> update the tracking fields, let component rerender

    _selectedPage = SelectedPage;
    _selectedPageElement = SelectedPageElement;

    return true;
}

Example fiddle illustrating the result here.

Upvotes: 0

Related Questions