I am having a hard time understanding when I should call StateHasChanged()
and when Blazor intercepts that something is changed so it must be re-rendered.
I
Generally speaking, the StateHasChanged() method is automatically called after a UI event is triggered, as for instance, after clicking a button element, the click event is raised, and the StateHasChanged() method is automatically called to notify the component that its state has changed and it should re-render.
When the Index component is initially accessed. The parent component renders first, and then the parent component renders its child.
Whenever the "Open" button is clicked the Index component re-renders (This is because the target of the event is the parent component, which by default will re-render (No need to use StateHasChanged). But not the child, who is not aware that his state has changed. In order to make the child aware that his state has changed and that it should re-render, you should add a call to the StateHasChanged method manually in the Show method. Now, when you click on the "Open" button, the child component is re-rendered first, and then its parent re-renders next. Now the red div is rendered visible.
Click the "Close" button to hide the red div. This time only the child component re-renders (This is because the target of the event is the child component, and it re-renders by default), but not the parent.
This behavior is correct and by design.
If you remove the call to the StateHasChanged method from the AddItem.Show method, define this
property: [Parameter] public EventCallback<bool> CloseEventCallback { get; set; }
, and add
a component attribute in the parent component to assign a value to this property like this:
<AddItem @ref="AddItem" CloseEventCallback="CallBack" />
, you'll notice no change outwardly,
but this time the order of re-rendering when the "Open" button is clicked, is first the parent
re-renders, then the child re-renders. This describes exactly the issue you've found expressed
in your question from the comments:
So, why my test 3 worked as expected even if CloseEventCallback isn't invoked anywhere?
You are right... I could not really explain this behvior before having a further investigation. I'll try to find out what is going on, and let you know.
AddItem's close method invoke the CloseEventCallback to advise the parent that it should re-render.
Note: your code define the CloseEventCallback with a boolean type specifier, so you must define a method in your parent component that has a boolean parameter. When you invoke the CloseEventCallback 'delegate' you actually call the Index.Callback method and you should pass it a boolean value. Naturally, if you passes a value to a component, you expect it to re-render so that the new state can be seen in the UI. And this is the functionality that the EventCallback provides: Though the event is triggered in the child component, its target is the parent component, which results in the parent component re-rendering.
I am wondering why a parent component should re-render itself if one of the subscribed EventCallback is invoked?
This is exactly what I'm trying to explain in the paragraph above. The EventCallback type was especially design to solve the issue of the event target, routing the event to the component whose state has changed (the parent component), and re-rendering it.