![](/img/trans.png)
[英]Blazor components: How to communicate from grandchild to child to parent or grandchild to parent
[英]Communicating from child to parent when using Components in Blazor
我有一個博客網站,評論在一個名為CommentList的Component
中進行管理。
index.razor
...
Counting comments: @CommentCount
<CommentList PostId="@CurrentPost.Id" OnCommentCountChanged="OnCommentCountChangedHandler" />
@code {
...
int CommentCount;
public void OnCommentCountChangedHandler(int count)
{
CommentCount = count;
}
}
現在是組件:
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);
}
正如您在上面的代碼中看到的那樣,在我的組件中,我通過一個服務檢索了這篇文章的所有評論,然后我調用了一個方法來通知父級計數。
檢索到評論列表后,我需要將計數傳達給父母。 我發現重新計算此計數( CountingComments )的唯一地方是OnParametersSetAsync
。
你會注意到我使用了一個標志。 沒有這個標志,就會有一個永無止境的循環:
OnParametersSetAsync
調用CountingComments
CountingComments
調用OnCommentCountChanged
OnParametersSetAsync
的調用有了標志,就可以避免循環,但我想知道這是否是最好的方法?
不幸的是,不可能區分每個參數的變化。 如果我們有 2 或 3 個參數,如果其中一個參數發生更改,則觸發OnParametersSetAsync
方法,但我們不知道涉及哪個參數。 此外,對EventCallback Parameter
OnCommentCountChanged的調用也會觸發此OnParametersSetAsync
而沒有興趣(在我的情況下)。
OnParametersSetAsync 方法中的代碼在每次執行該方法時都會多余地檢索注釋。 相反,您應該在創建 CommentList 組件時使用 OnInitalized(Async) 方法對僅檢索一次數據。
現在有了這種設計,只有在當前帖子(博客的,請注意)中添加了新評論時,您才需要通過再次調用 CommentService.GetComments 方法來刷新AllComments
列表。 如何調用、何時調用等都取決於您的設計。
讓我在這里描述一個簡單可行的設計。 假設在您的博客文章底部是一個評論部分,您可以在其中輸入評論,然后單擊“保存我的評論”按鈕。 您可以定義一個服務或 Razor 組件來將添加的評論發布到相關的數據庫表中。 此服務或組件還應具有調用事件的代碼,以通知您的 CommentList 發生這種情況(添加了新評論)。 作為響應,您的代碼應調用 CommentService.GetComments 方法從數據庫中檢索一組新的評論。
不幸的是,無法區分每個參數的變化
為什么不?
這就是你應該如何定義你的[Parameter] public int PostId { get; set; }
[Parameter] public int PostId { get; set; }
[Parameter] public int PostId { get; set; }
private int _internalPostId;
private int InternalPostId
{
get => _internalPostId;
set
{
if(_internalPostId != value)
{
_internalPostId = value;
// Can only be true if a new post is displayed or selected
// in the Index component, which requires you to retrieve the
// comments for the new post id passed. Put here code that
// call the method that perform the database access to
// retrieve the comments. That should be the same code that
// you should have in OnInitalized(Async) pair of methods. So
// you can create a single method that should be called from
// OnInitalized(Async), and from here.
// Understand that OnInitalized(Async) is called only once,
// when the component is created... When the PostId parameter
// changes, the Component is not created again, but re-used.
// Note: If you define an asynchronous method that contain the
// code to retrieve the comments, you can still call it from
// here by applying the so-called fire-and-forget operation,
// as for instance: _ = MyService.GetSomething();
}
}
}
請注意,我引入了一個名為InternalPostId
的新私有屬性。 使用它是因為子組件不應該改變參數屬性......它們應該被視為自動屬性。 希望你不會感到困惑。
您還需要重寫 OnParametersSet 方法,以便從 PostId 參數屬性更新內部屬性 InternalPostId。
protected override void OnParametersSet()
{
if (InternalPostId != PostId)
{
InternalPostId = PostId;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.