Svelte加载外键关联值不生效显示undefined/Promise对象问题
问题根因
你遇到的渲染异常和重渲染机制关系不大,是代码里的几个逻辑问题叠加导致的:
Array.prototype.forEach不支持异步等待,你写await columns.forEach(async () => {})属于无效写法,外层逻辑不会等待内部axios请求完成,首次渲染时关联数据大概率还没拉取完成- Svelte的响应式更新依赖顶层变量的重新赋值触发:你获取到主列表数据后,直接遍历修改数组内对象的属性(给row追加company字段),没有重新对
data变量做赋值,Svelte检测不到数据变更,自然不会触发视图更新 - 模板渲染逻辑有问题:外键列你一直读的是
row[column.column],对应字段是company_id,就算你给row加了存公司名的company属性,模板也根本没读这个字段 - 附带一个隐藏bug:你写的删除按钮
on:click={deleteEntity(row._id)}会在组件渲染时直接触发删除操作,不需要等点击。你之前点测试按钮能看到正确值,本质是点击时所有异步请求已经执行完成,触发了控制台的懒求值,和渲染逻辑本身无关。
修复步骤
1. 修正异步数据加载逻辑
把forEach异步循环换成for...of保证请求按顺序等待执行,所有数据处理完成后统一赋值给data触发响应式:
async function loadData() { try { const mainRes = await axios.get(`http://localhost:3001/api/${entityType}`); let tableData = mainRes.data; for (const column of columns) { if (column.type !== "foreignEntity") continue; const foreignKey = column.column; const entityField = foreignKey.replace("_id", ""); const foreignEntityPath = pluralize.plural(entityField); const foreignRes = await axios.get(`http://localhost:3001/api/${foreignEntityPath}`); const foreignList = foreignRes.data; tableData = tableData.map(row => { const target = foreignList.find(item => item._id === row[foreignKey]); return { ...row, [entityField]: target?.name || "" }; }); } // 统一赋值触发Svelte响应式更新 data = tableData; } catch (err) { console.error("数据加载失败:", err); } } // 组件初始化时调用加载方法 loadData();
把你原来写在script顶层的axios加载逻辑删掉,换成上面的方法即可。
2. 修正模板渲染逻辑
针对外键类型的列,单独读取存关联名称的字段,不要读原始id字段;同时修复删除按钮的点击事件写法:
<tbody> {#each data as row} <tr> {#each columns as column} {#if column.type === "image"} <td><img src={row[column.column]} alt="" style="height: 35px"></td> {:else if column.type === "foreignEntity"} <!-- 外键列读取去掉_id后缀的字段,也就是我们存公司名的字段 --> <td>{row[column.column.replace("_id", "")]}</td> {:else} <td>{row[column.column]}</td> {/if} {/each} <td> <a href={`/#/${entityType}/${row._id}`} class="btn btn-primary btn-sm m-0">Ansehen</a> <a href={`/#/${entityType}/${row._id}/edit`} class="btn btn-primary btn-sm m-0">Bearbeiten</a> <!-- 事件包一层箭头函数,避免渲染时直接触发 --> <button on:click={() => deleteEntity(row._id)} class="btn btn-danger btn-sm m-0">Löschen</button> </td> </tr> {/each} </tbody>
改完之后不需要额外手动触发重渲染,Svelte会在data赋值后自动更新视图。
内容的提问来源于stack exchange,提问作者Luca K.
相关产品推荐
相关产品推荐

