React useEffect调用回调函数获取BIM属性时setState偶发无响应问题
问题根因
该偶发问题是异步时序不匹配导致的:
model.getProperties是Autodesk Viewer提供的异步API,调用后不会立刻返回结果- 你在循环中批量触发了大量属性查询请求,还未等所有请求执行完成、所有属性都写入
histogram对象,就提前调用cb(histogram)返回了结果 - 刷新页面后表现正常,是因为模型数据、接口响应被浏览器缓存,异步请求返回速度变快,刚好在回调触发前所有查询都已执行完成
修复方案
将回调式写法改造为Promise异步等待写法,确保所有属性查询完成后再返回结果:
第一步:改造getAllLeavesProperties方法
//Get All Leavs Props export const getAllLeavesProperties = ( allModels: Autodesk.Viewing.GuiViewer3D | undefined ): Promise<Record<string, any>> => { // histogram放到函数内部,避免外部变量污染导致的历史数据干扰 const histogram: Record<string, any> = {} const allLoadedViewers = isolateAndColorObject( allModels as Autodesk.Viewing.GuiViewer3D ); // 外层先等待dbId获取完成 return new Promise((resolve) => { getAllLeavesDbId(allModels, (dbId: number[]) => { // 收集所有属性查询的Promise const propertyPromises: Promise<void>[] = [] dbId.forEach((id) => { if (allLoadedViewers && id) { for (let model of allLoadedViewers) { if (model) { // 把每个getProperties调用包装成Promise,放到数组里统一等待 const pro = new Promise<void>((res) => { model.getProperties(id, (props) => { for (let prop of props.properties) { if (!prop) return; if (!histogram[prop.displayName]) { histogram[prop.displayName] = {}; } if (!histogram[prop.displayName][prop.displayValue]) { histogram[prop.displayName][prop.displayValue] = []; } histogram[prop.displayName][prop.displayValue].push(props.dbId); } res() }) }) propertyPromises.push(pro) } } } }); // 等待所有属性查询完成后,再返回最终的histogram Promise.all(propertyPromises).then(() => resolve(histogram)) }); }) };
第二步:改造调用逻辑
const test = async () => { if (!allModels) return; try { const data = await getAllLeavesProperties(allModels) const BIM7AATypeComments = data["BIM7AATypeComments"]; if (BIM7AATypeComments) { const label = Object.keys(BIM7AATypeComments); if (label) setTt(label); const myObject = Object.keys(BIM7AATypeComments).map( (key) => BIM7AATypeComments[key].length ); if (myObject) setrr(myObject); } } catch (error) { console.log(error) } }; React.useEffect(() => { let isMounted = true // 加组件卸载判断,避免组件销毁后setState引发的内存泄漏警告 if (isMounted) { test(); } return () => { isMounted = false } }, [allModels]); // 把allModels加到依赖项里,模型加载完成后自动重新触发查询
内容的提问来源于stack exchange,提问作者Abed Aarabi
相关产品推荐
相关产品推荐

