我正在研究一个读取CSV文件并在文件上的每一行发送请求的组件。该过程运行良好,但是随着线路成功发布,我试图显示反馈。问题在于,使用useState挂钩时,set函数在调用函数时即通过,而不是在每个promise已解决之后才传递。因此,我无法追加到成功的结果数组中,该数组不断被上次成功调用替换。 为了避免服务器过载,API调用会被消退一秒钟。
import React, {useState} from "react";
import CSVReader from "react-csv-reader";
import {post} from "../api";
function App() {
const [inserts, setInserts] = useState([])
const callApi = async (x) => {
let item = {
date: x.date,
value: x.value,
};
await post(`add-items`, item);
setInserts([...inserts, item])
};
const debouncedApiCall = (body, delay) => {
return new Promise((resolve) => {
const handler = () => callApi(body).then((x) => resolve(x));
setTimeout(handler, delay);
});
};
const insert = async (rows) => {
let timer = 0;
await Promise.all(
rows.map(async (x) => {
timer++;
return await debouncedApiCall(x, timer * 1000);
})
);
};
let onFileLoaded = (data) => {
insert(data).then((x) => console.log(x));
};
return (
<div>
<CSVReader onFileLoaded={onFileLoaded}/>
{JSON.stringify(inserts)}
</div>
);
}
export default App;
答案 0 :(得分:1)
调用呼叫API函数时,在其闭包内捕获inserts
的状态。这意味着inserts
并不总是最新的。最终得到的结果称为“ stale closure”。
要解决此问题,useState方法提供的变异函数可以接受回调函数。调用函数时,此回调函数可以接收最新状态。这对异步操作很有帮助。
您的callApi函数将变为
const callApi = async (x) => {
let item = {
date: x.date,
value: x.value,
};
await post(`add-items`, item);
setInserts(prevState => [...prevState , item]) //prevState gets the latest state of inserts when setInserts is called
return (x); //will return this value once this async function finishes. similar to resolve(x)
};
我无法完全调试您的代码,但我认为这是不必要的步骤。您应该可以更改插入函数以等待所有callApi的调用,并且只需从callApi函数返回x(如我在上面添加的内容)即可。
const insert = async (rows) => {
let timer = 0;
await Promise.all(
rows.map((x) => {
return callApi(x); //Promise.All wants an array of promises. async functions return a promise
})
);
};
作为旁注,Promise.all返回一个promise,其中包含所有promise结果的实际数组结果。您可以通过在Promise.All上添加.then来获取它们,然后从insert函数中删除异步,或等待结果。
基于异步:插入会返回一个承诺,因此您需要在调用函数中进行处理。
const insert = async (rows) => {
let timer = 0;
const results = await Promise.all(
rows.map((x) => {
return callApi(x); //Promise.All wants an array of promises. async functions return a promise
})
);
return results; //array of all your x values for each row
};
基于非异步:行尾,insert是调用函数
const insert = (rows) => {
let timer = 0;
Promise.all(
rows.map((x) => {
return callApi(x); //Promise.All wants an array of promises. async functions return a promise
})
).then((result) => {
//result is an array of all x values according to rows
});
};