I have a blog website where comments are managed inside a Component called CommentList.
index.razor
...
Counting comments: @CommentCount
<CommentList PostId="@CurrentPost.Id" OnCommentCountChanged="OnCommentCountChangedHandler" />
@code {
...
int CommentCount;
public void OnCommentCountChangedHandler(int count)
{
CommentCount = count;
}
}
And now the component:
CommentList.razor
[Parameter] public int PostId { get; set; }
[Parameter] public EventCallback<int> OnCommentCountChanged { get; set; }
[Inject] ICommentService CommentService { get; set; }
List<Comment> AllComments { get; set; }
bool flag;
protected override async Task OnParametersSetAsync()
{
if (PostId && !flag)
{
flag = true;
AllComments = await CommentService.GetComments(PostId);
await CountComments();
}
}
protected async Task CountComments()
{
Console.WriteLine("CountComments called");
if (AllComments == null) return;
var count = AllComments.Count();
await OnCommentCountChanged.InvokeAsync(count);
}
As you can see on the code above, in my component, I retrieved all the comments for this post though a service then I invoke a method to inform the parent of the count.
I needed to communicate the count to the parent as soon as I retrieved the list of comments. The only place I found for recomputing this count (CountingComments) was in OnParametersSetAsync.
You'll notice that I used a flag. Without this flag, there is a never ending loop:
- Calling
CountingCommentsfromOnParametersSetAsync - Invoking
OnCommentCountChangedfromCountingComments - This 'invoking' produce a call to
OnParametersSetAsync - Etc...
With the flag in place the loop is avoided but I wonder if this is the best approach ?
Unfortunately it is not possible to make the distinction between each parameter changes. If we have 2 or 3 parameters, if one of these parameters changed, the method OnParametersSetAsync is triggered but we don't have any idea which parameter is concerned. Furthermore an invoke to the EventCallback Parameter OnCommentCountChanged also trigger this OnParametersSetAsync with no interest (in my case).
The code in the OnParametersSetAsync method retrieve the comments superfluously at each execution of the method. Instead you should use OnInitalized(Async) pair of methods to retrieve the data only once, when your CommentList component is created.
Now with that design, only when a new comment is added to the current post (of the blog, mind you), you'll need to refresh the
AllCommentslist by calling the CommentService.GetComments method again. How to call, when to call, etc. is all depending on your design.Let me describe here an easy and workable design. Say at the bottom of your blog post is a comment section where you can enter a comment, and then click on a "Save my comment" button. You can define a service or Razor component to post the added comment to the relevant database table(s). This service or component should also have code to invoke an event that notify your CommentList of this occurrence (new comment added). In response, your code should call the CommentService.GetComments method to retrieve a fresh set of comments from the database.
Why not ?
This is how you should define your
[Parameter] public int PostId { get; set; }Note that I've introduced a new private property called
InternalPostId. It is used because parameter properties should not be mutated by the child component... They should be treated as auto properties. Hope you're not confused.You'll also need to override the OnParametersSet method in order to update the internal property InternalPostId from the PostId parameter property.