简体   繁体   中英

StateHasChanged for specific component instead rerender all components in a page

I am using multiple components is my application each are rendered in conditional manner. Is there any possibilities to re-render a specific component alone?

MyRazor.razor file,

 <button @onclick="Chnage">Second</button>
<div>
    @if (renderOne)
    {
        var data1 = Count++;
        <ComponentFirst>@data1</ComponentFirst>
    }
    @if (renderTwo)
    {
        var data2 = Count2++;
        <ComponentSecond class="btn-danger">@data2</ComponentSecond>
     }
</div>
@code { 
    void Chnage()
    {
        renderOne = true;
    }
}

ComponentFirst and ComponentSecond are rendered by checking by respective booleans. In the button click, I have enable CompoenentFirst alone. But the ComponentSecond also rendered again. My aim is If I enable renderOne ComponentFirst alone should be rendered again. If I disable renderTwo ComponentTwo alone should rendered again instead of rendering both components for a single change in the application.

You probably shouldn't be worried about a component rendering lots of times. Rendering only builds a rendertree, it doesn't update the browser's DOM. Only once the whole page's render tree is built will Blazor compare it against the last render tree and then update the DOM from the diff.

Having said that:

If the parent passes any information to the child component via a [Parameter] property (including a RenderFragment ) then whenever the parent component re-renders the child component will also re-render just in case anything has altered.

If you want components to re-render independently of their parents then you should not pass any state down to them. You can achieve this by storing state outside of the components. For example

public class MyState
{
  public int Count1 { get; set; }
  public int Count2 { get; set; }

  public event EventHandler<EventArgs> Changed;
  public void NotifyChanged() => Changed?.Invoke(this, EventArgs.Empty);
}

If you register that as an injectable dependency then you can consume it directly in the child component

@inject MyState State
@implements IDisposable

<div>
  The value is @State.Count1
</div>

@code
{
  protected override void OnInitialized()
  {
    State.Changed += DoUpdate;
  }

  void IDisposable.Dispose()
  {
    State.Changed -= DoUpdate; // Important1
  }

  private void DoUpdate(object sender, EventArgs e)
  {
    InvokeAsync(StateHasChanged);
  }
}

Any component can update the state by injecting MyState and then doing

injectedState.Counter1++;
injectedState.Counter2--;
injectedState.NotifyChanged();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM