material-table onRowUpdate后数据库更新成功但表格未同步加载问题
我用material-table结合远程数据,通过API从数据库取数,配置了onRowAdd和onRowUpdate编辑功能。现在遇到的问题是:更新行数据后,数据库已经成功更新,但表格必须刷新浏览器才会显示新数据。查服务器日志发现,material-table在后端更新完成前就触发了表格刷新,所以拿到的还是旧数据。推测是onRowUpdate返回的Promise还没完成,表格就发起了远程数据查询。
我的疑问:
- 怎么让material-table等
onRowUpdate的Promise完成后再刷新表格? onRowAdd功能正常,新增行能直接显示,是不是material-table对onRowAdd的处理逻辑不一样?
另外,要是在API获取数据前留时间让更新请求完成,表格就能正确显示新数据,这也验证了是异步刷新导致的问题。
代码示例
<MaterialTable style={{backgroundColor: 'rgb(226, 231, 235)'}} icons={tableIcons} columns={tableColumns} data={query => new Promise((resolve, reject) => { axios.get( props.apiURL + "menu-groups", { headers: {"Content-Type": "application/json", "Request-ID": transactionId, "Source-System": SOURCE_SYSTEM, "Authorization": "Bearer " + someToken} } ) .then(response => { props.onChange(response.data); resolve({ data: response.data, page: null, totalCount: response.data.length }); }) .catch(error => { console.error(error); reject(error); }) setTransactionId(uuid()); }) } title="Menu Groups" editable={{ onRowAdd: (newData) => new Promise<void>((resolve, reject) => { setTimeout(() => { axios.post(props.apiURL + "menu-groups", JSON.stringify(newData), { headers: {"Content-Type": "application/json", "Request-ID": transactionId, "Source-System": SOURCE_SYSTEM, "Authorization": "Bearer " + someToken} } ) .then(response => { resolve(); }) .catch(error => { console.error(error); reject(error); }) setTransactionId(uuid()); }, 1000); }), onRowUpdate: (newData, oldData) => new Promise<void>((resolve, reject) => { setTimeout(() => { axios.put(props.apiURL + "menu-groups" + "/" + newData.id, JSON.stringify(newData), { headers: {"Content-Type": "application/json", "Request-ID": transactionId, "Source-System": SOURCE_SYSTEM, "Authorization": "Bearer " + someToken } ) .then(response => { resolve(); }) .catch(error => { console.error(error); reject(error); }) setTransactionId(uuid()); }, 1000); }), onRowDelete: (oldData) => new Promise<void>((resolve, reject) => { setTimeout(() => { axios.delete(props.apiURL + "menu-groups" + "/" + oldData.id, { headers: {"Content-Type": "application/json", "Request-ID": transactionId, "Source-System": SOURCE_SYSTEM, "Authorization": "Bearer " + someToken} } ) .then(response => { resolve(); }) .catch(error => { console.error(error); reject(error); }) setTransactionId(uuid()); }, 1000); }) }} />
问题解答
1. 让material-table等待onRowUpdate完成后再刷新的方案
核心问题是你在axios请求完成前就执行了setTransactionId(uuid()),甚至提前resolve了Promise,导致表格触发刷新时后端更新还没完成。需要确保Promise只有在后端请求完全成功后才结束,同时调整setTransactionId的执行时机:
修改onRowUpdate逻辑
onRowUpdate: (newData, oldData) => new Promise<void>((resolve, reject) => { // 移除不必要的setTimeout,避免人为延迟 axios.put(props.apiURL + "menu-groups/" + newData.id, JSON.stringify(newData), { headers: { "Content-Type": "application/json", "Request-ID": transactionId, "Source-System": SOURCE_SYSTEM, "Authorization": "Bearer " + someToken } }) .then(response => { setTransactionId(uuid()); // 后端更新成功后再更新transactionId resolve(); // 此时再通知表格可以触发刷新 }) .catch(error => { console.error(error); reject(error); }) }),
修正data回调中的时序问题
原代码中setTransactionId在axios.get发起后立即执行,会导致当前请求用的transactionId被提前修改,引发时序错误,需要移到请求完成后:
data={query => new Promise((resolve, reject) => { axios.get( props.apiURL + "menu-groups", { headers: { "Content-Type": "application/json", "Request-ID": transactionId, "Source-System": SOURCE_SYSTEM, "Authorization": "Bearer " + someToken } }) .then(response => { props.onChange(response.data); resolve({ data: response.data, page: null, totalCount: response.data.length }); setTransactionId(uuid()); // 请求完成后再更新transactionId }) .catch(error => { console.error(error); reject(error); setTransactionId(uuid()); // 失败场景也更新 }) }) }
2. onRowAdd正常的原因
material-table对onRowAdd的处理逻辑确实不同:当你完成onRowAdd的Promise后,它会先把新数据临时添加到本地表格缓存,然后再触发远程数据刷新。如果刷新后的返回数据包含这条新记录,就会替换本地缓存;如果没包含,也会保留本地缓存,所以你会看到新增行直接显示。
而onRowUpdate没有本地缓存更新的逻辑,完全依赖远程数据刷新获取最新行数据。当你的更新请求还没完成,表格就发起刷新,拿到的还是旧数据,自然看不到更新效果。
内容的提问来源于stack exchange,提问作者Bach

