Bob5421
Bob5421

Reputation: 9143

StateHasChanged goal in Blazor

Look at this very basic component:

<div>
    @param1
    <button @onclick="@btn_on_click">Cliquez là</button>
</div>

@code
{
    [Parameter]
    public int param1 { get; set; }

    [Parameter]
    public Action<int> on_evt_test_fire { get; set; }

    void btn_on_click()
    {
        param1 += 1;
        this.on_evt_test_fire(param1);
    }
}

And look at this very basic Page:

@message

<button @onclick="@on_btn_click">Click me</button>

<MyComponent param1="1"  on_evt_test_fire="@on_evt" />
<MyComponent param1="2" on_evt_test_fire="@on_evt" />

@code 
{
    private String message = "";

    private void on_evt(int param_evt)
    {
        message = "Button clicked inside component";

        StateHasChanged();
    }

    private async Task on_btn_click()
    {
        message = "Button clicked in this page";
    }
}

I have a problem with StateHasChanged().

Thanks for your help

Upvotes: 1

Views: 884

Answers (3)

enet
enet

Reputation: 45684

whereas it is not necessary in on_btn_click

It is not necessary on on_btn_click because the StateHasChanged method is automatically called on UI events.

[Parameter]
  public Action<int> on_evt_test_fire { get; set; }

You shouldn't use the Action delegate. Use EventCallback 'delegate' instead, like this:

Note: When you use the Action delegate the target of the event is the current component ( child component), but when you use EventCallback, the target is the parent component, which is why you don't need to add the call to the StateHasChanged method. Before the EventCallback was discovered, we had to call the StateHasChanged method. It was ages ago...

[Parameter]
public EventCallback<int> on_evt_test_fire { get; set; }

And you should call it like this:

public async Task btn_on_click()
{
   if( on_evt_test_fire.HasDelegate)
   {
       temp++;
       await on_evt_test_fire.InvokeAsync(temp);
    }
 }

You shouldn't use the param1 parameter to increment its value. Define a new variable and assigned it the value of param1 in the OnInitialized method like this:

  protected override void OnInitialized()
  {
      temp = param1;
  }

When i call StateHasChanged(), the 2 components are reset: They take their initial values..

--

Don't create components that write to their own parameter properties Parameters are overwritten under the following conditions:

  • A child component's content is rendered with a RenderFragment.

  • StateHasChanged is called in the parent component. Parameters are reset because the parent component rerenders when StateHasChanged is called and new parameter values are supplied to the child component.

Source here:

See more here:

Upvotes: 2

Nik FP
Nik FP

Reputation: 3073

The answers from both @Henk and @SilenceAmongCrows are correct. One more thing to add is that in your child component, if you use EventCallBack<T> instead of Action<T> and have your param1 property in your child component bound to a property in your @code block of the parent component, the Blazor engine will do a much better job of tracking what to refresh and when to do so.

Upvotes: 0

Skuffd
Skuffd

Reputation: 363

I believe the @onClick callback forces a child re-render due to some hidden logic. Your callback or event when assign to the button's @onClick is most likely being added to a list of things that onClick does internally. Take this with a grain of salt, this is just my theory.

Edit: your parameters being reset are because of the setState() forcing your parent to re-render from the ground up with the hard coded "1" and "2". When the event triggers for the onbuttonclicked, I believe it sets the state internally within the components, thus retaining data. More salt.

Upvotes: 0

Related Questions