Blazor 8(Server)状态管理:跨组件共享值与异步操作处理
解决方案:统一支持同步/异步回调的状态类实现
不需要定义两个状态事件,只需修正状态类的事件类型和触发逻辑,就能同时支持父组件的同步处理和Child2的异步操作。以下是正确的实现方式:
1. 修正状态类MyState
将事件类型改为Func<Task>?(支持异步回调),并修改SetSharedValue为异步方法,确保所有异步回调被正确等待:
public class MyState { // 替换原有的Func<Action>,使用Func<Task>支持异步回调 public event Func<Task>? StateChanged; public string SharedValue { get; private set; } = string.Empty; public async Task SetSharedValue(string value) { SharedValue = value; // 先获取当前所有订阅者,避免触发过程中订阅关系变更导致异常 var handlers = StateChanged; if (handlers != null) { // 遍历每个订阅者并await,确保异步操作执行完成 foreach (var handler in handlers.GetInvocationList().Cast<Func<Task>>()) { await handler(); } } } }
2. Child1调用方式
由于SetSharedValue改为异步方法,调用时需要加await:
// Child1.razor.cs await MyState.SetSharedValue("Hey");
3. Child2订阅异步回调并处理销毁
实现IDisposable接口,在组件销毁时取消订阅,防止内存泄漏:
// Child2.razor.cs public class Child2 : ComponentBase, IDisposable { [Inject] private MyState MyState { get; set; } = default!; // 假设第三方组件已注入或初始化 private ThirdPartyComponent thirdPartyComponent = default!; protected override void OnInitialized() { MyState.StateChanged += HandleStateChangedAsync; } private async Task HandleStateChangedAsync() { // 执行第三方异步刷新方法 await thirdPartyComponent.RefreshDataAsync(); // 若需要更新组件UI,手动调用StateHasChanged StateHasChanged(); } public void Dispose() { // 取消订阅事件 MyState.StateChanged -= HandleStateChangedAsync; } }
4. 父组件订阅实现
父组件无论是同步还是异步处理,都可以直接订阅同一个事件:
// Page.razor.cs public class Page : ComponentBase, IDisposable { [Inject] private MyState MyState { get; set; } = default!; protected override void OnInitialized() { MyState.StateChanged += ParentHandleStateChanged; } // 同步处理逻辑可使用async Task(或async void,推荐前者) private async Task ParentHandleStateChanged() { // 父组件的业务逻辑,比如更新本地状态、刷新UI StateHasChanged(); } public void Dispose() { MyState.StateChanged -= ParentHandleStateChanged; } }
关键说明
- 原修改中使用
Func<Action>是错误的,该类型代表返回Action的委托,而非异步委托,导致父组件无法正常订阅。正确的异步事件类型应为Func<Task>。 - 触发事件时必须先获取当前订阅者列表,避免遍历过程中订阅关系变更引发异常。
- 所有订阅事件的组件都需实现
IDisposable,在销毁时取消订阅,防止内存泄漏。 - 异步回调后若需更新UI,需手动调用
StateHasChanged(),因为异步操作可能脱离Blazor的同步上下文。
内容的提问来源于stack exchange,提问作者chobo2
相关产品推荐
相关产品推荐

