
本文深入探讨了在hilla/vaadin应用中,使用`vaadin-grid`绑定异步数据时常见的promise类型错误及其解决方案。核心问题在于对`vaadin-grid.items`属性的错误绑定、异步方法中`promise`的未正确解析以及mobx `runinaction`的误用。通过纠正数据绑定、合理运用`async/await`和理解mobx状态管理,确保数据能够正确加载并显示在grid中。
在Hilla/Vaadin框架中构建富客户端应用时,常常需要从后端服务获取数据并将其展示在vaadin-grid等UI组件中。由于数据获取通常是异步操作,若不正确处理JavaScript Promise和数据绑定机制,便可能遭遇“Type 'Promise
出现此类错误通常是以下几个方面的问题交织导致的:
下面,我们将结合一个实际案例来逐一解决这些问题。
假设我们有一个Hilla后端服务,提供获取产品类别列表的端点,以及一个前端MobX Store来管理这些数据,并最终在vaadin-grid中展示。
后端服务 (ProductEndpoint.java):
@Endpoint
@AnonymousAllowed
public class ProductEndpoint {
// ... 其他方法 ...
public @Nonnull List<@Nonnull ProductCategoryDataList> fetchAllProdCategory() {
return this.productService.fetchProductCategory(""); // 返回一个List
}
// ...
}后端端点返回的是一个List,Hilla会自动将其转换为前端的Promise<ProductCategoryDataList[]>。
MobX Store (ProductStore.ts):
export class ProductStore {
constructor() {
makeAutoObservable(this);
this.fetchProductCatgeory(); // 构造时调用
}
async fetchProductCatgeory() {
const prodCatData = await ProductEndpoint.fetchAllProdCategory();
runInAction(() => {
return prodCatData; // 问题点:在runInAction中返回,但外部没有接收
});
}
}视图层Store (CategoryListRegisterViewStore.ts):
export class CategoryListRegisterViewStore {
categoryList: ProductCategoryDataList[] = [];
constructor() {
makeAutoObservable(this, { categoryList: observable.shallow });
this.loadProductCategory(); // 构造时加载数据
}
loadProductCategory() {
const prodCategory = appStore.tricampCrmProductStore.fetchProductCatgeory(); // 问题点:prodCategory此时是一个Promise
runInAction(() => {
this.categoryList = prodCategory; // 问题点:将Promise赋值给了数组类型
});
}
}UI组件 (HTML 模板):
<vaadin-grid theme="row-stripes" .items="${categoryListRegisterViewStore.loadProductCategory}" >
<!-- ... 列定义 ... -->
</vaadin-grid>问题点:items属性绑定到了一个方法,而非一个数据数组。
我们将从UI层向上层逐一修正。
vaadin-grid的items属性应该绑定到实际的数据数组,而不是加载数据的方法。数据加载方法负责更新这个数组,而Grid则直接从数组中获取数据。
错误代码:
<vaadin-grid theme="row-stripes" .items="${categoryListRegisterViewStore.loadProductCategory}" >正确代码:
<vaadin-grid theme="row-stripes" .items="${categoryListRegisterViewStore.categoryList}" >
<!-- ... 列定义 ... -->
</vaadin-grid>现在,vaadin-grid将直接观察categoryListRegisterViewStore.categoryList数组的变化,并在数据更新时自动刷新。
loadProductCategory方法负责触发数据加载,并等待异步操作完成后,将解析后的数据赋值给categoryList。
错误代码:
loadProductCategory() {
const prodCategory = appStore.tricampCrmProductStore.fetchProductCatgeory();
runInAction(() => {
this.categoryList = prodCategory; // prodCategory 此时是 Promise<ProductCategoryDataList[]>
});
}这里的问题在于,fetchProductCatgeory()返回的是一个Promise,而不是ProductCategoryDataList[]数组。直接将其赋值给this.categoryList会导致类型不匹配错误。我们需要使用await关键字等待Promise解析。
正确代码:
export class CategoryListRegisterViewStore {
categoryList: ProductCategoryDataList[] = [];
constructor() {
makeAutoObservable(this, { categoryList: observable.shallow });
this.loadProductCategory();
}
async loadProductCategory() { // 标记为 async
const prodCategory = await appStore.tricampCrmProductStore.fetchProductCatgeory(); // 使用 await
runInAction(() => {
this.categoryList = prodCategory; // prodCategory 此时是解析后的数据数组
});
}
// ...
}通过将loadProductCategory标记为async并使用await,我们确保prodCategory变量接收到的是Promise解析后的实际数据数组。runInAction在这里的作用是确保对this.categoryList的赋值操作在MobX的action中进行,从而正确触发UI更新。
ProductStore中的fetchProductCatgeory方法旨在从Hilla端点获取数据并返回一个Promise。然而,原始代码在runInAction中返回数据,导致外部调用者无法正确获取到Promise。
错误代码:
async fetchProductCatgeory() {
const prodCatData = await ProductEndpoint.fetchAllProdCategory();
runInAction(() => {
return prodCatData; // 这里的 return 仅对 runInAction 内部有效,不会成为 fetchProductCatgeory 的返回值
});
}async函数默认返回一个Promise。如果函数体内没有显式返回,或者在runInAction等回调中返回,其外部的Promise将解析为undefined或void。
正确代码:
export class ProductStore {
constructor() {
makeAutoObservable(this);
// 可以在这里直接调用 fetchProductCatgeory,但需注意其返回 Promise
// 如果需要在构造函数中等待数据,则构造函数也需为 async,或使用 .then()
}
// 推荐直接返回 Hilla 端点调用的 Promise
fetchProductCatgeory(): Promise<ProductCategoryDataList[]> {
return ProductEndpoint.fetchAllProdCategory();
}
// 或者,如果确实需要 await 并在内部处理,但通常不建议在这里使用 runInAction
// async fetchProductCatgeory(): Promise<ProductCategoryDataList[]> {
// const prodCatData = await ProductEndpoint.fetchAllProdCategory();
// // 这里没有状态修改,所以不需要 runInAction
// return prodCatData;
// }
}最简洁且推荐的方式是让fetchProductCatgeory直接返回ProductEndpoint.fetchAllProdCategory()的Promise。这样,上层调用者(如CategoryListRegisterViewStore.loadProductCategory)就可以直接await这个Promise。
以下是经过修正后的CategoryListRegisterViewStore和ProductStore以及vaadin-grid的绑定方式:
ProductStore.ts (简化版):
import { makeAutoObservable } from 'mobx';
import { ProductEndpoint } from 'Frontend/generated/endpoints'; // 假设路径
import { ProductCategoryDataList } from 'Frontend/generated/endpoints'; // 假设路径
export class ProductStore {
constructor() {
makeAutoObservable(this);
}
// 直接返回 Hilla 端点调用的 Promise
fetchProductCatgeory(): Promise<ProductCategoryDataList[]> {
return ProductEndpoint.fetchAllProdCategory();
}
// 其他方法...
}CategoryListRegisterViewStore.ts:
import { makeAutoObservable, runInAction, observable } from 'mobx';
import { ProductCategoryDataList } from 'Frontend/generated/endpoints'; // 假设路径
import { appStore } from './AppStore'; // 假设 appStore 包含 ProductStore 实例
export class CategoryListRegisterViewStore {
categoryList: ProductCategoryDataList[] = [];
constructor() {
makeAutoObservable(this, {
categoryList: observable.shallow,
});
this.loadProductCategory(); // 在构造函数中触发数据加载
}
async loadProductCategory() {
try {
const prodCategory = await appStore.tricampCrmProductStore.fetchProductCatgeory();
runInAction(() => {
this.categoryList = prodCategory;
});
} catch (error) {
console.error("Failed to load product categories:", error);
// 可以在这里处理错误,例如显示错误消息
}
}
// 其他方法...
}
// 导出 store 实例,供视图层使用
export const categoryListRegisterViewStore = new CategoryListRegisterViewStore();HTML 模板 (或 LitElement/TypeScript 视图组件):
<vaadin-grid theme="row-stripes" .items="${categoryListRegisterViewStore.categoryList}" >
<vaadin-grid-column header="Category Name" path="name"></vaadin-grid-column>
<!-- 假设 ProductCategoryDataList 有一个 'name' 属性 -->
<vaadin-grid-column header="Description" path="description"></vaadin-grid-column>
<!-- ... 其他列定义 ... -->
</vaadin-grid>在Hilla/Vaadin应用中处理异步数据和vaadin-grid数据绑定时,关键在于正确理解Promise的工作机制、async/await的用法以及MobX状态管理的原则。通过将vaadin-grid.items绑定到已解析的数据数组、在异步方法中正确使用await解析Promise,并避免runInAction的误用,可以有效避免常见的类型错误,确保数据能够顺畅地流动并正确展示在用户界面上。遵循这些最佳实践,将有助于构建更稳定、可维护的Hilla/Vaadin应用。
以上就是Hilla/Vaadin Grid数据绑定与异步数据处理深度解析的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号