我有一个组件,里面我正在与API通信(这里我把超时放在模拟上(。我在循环内部进行了一些调用,以更新当前交互索引上的数组。实际上,我想控制台.log所有带有添加数据的数组。这就是问题所在。Loop 正在经历所有迭代,并且不会等待完成异步任务,因此它会打印带有注释的空数组,说明有数据,但现在才刚刚出现。
我试图添加useState,但没有解决问题。
import React, {useEffect} from 'react';
function Ingredients() {
const heatingStepsTime = [];
const heatingStepsTimer = [];
function getTimes(i, type) {
if (type === "time") {
setTimeout(() => {
heatingStepsTime[i] = i;
}, 1000);
} else {
setTimeout(() => {
heatingStepsTimer[i] = i + 1;
}, 1000)
}
}
const getProcess = () => {
for (let i = 0; i < 3; i++) {
getTimes(i, "time");
getTimes(i, "timer");
}
};
useEffect(getProcess, []);
console.log(heatingStepsTime);
console.log(heatingStepsTimer);
return (
<div className="App">
test
</div>
);
}
export default Ingredients;
有没有办法在 React 中停止循环迭代,以便在非同步任务完成时继续?
试试这个
function App() {
function getTimes(i) {
return new Promise(resolve => {
setTimeout(() => {
resolve(i);
}, 1000);
});
}
const [heatingStepsTime, setHeatingStepsTime] = useState([]);
const getProcess = () => {
const promises = '0'.repeat(10).split('').map((c, i)=>getTimes(i));
Promise.all(promises)
.then(result=> setHeatingStepsTime(result));
};
useEffect(getProcess, []);
return (
<div className="App">
{heatingStepsTime.map((p,i)=><div key={i}>{p}</div>)}
</div>
);
}
https://stackblitz.com/edit/react-szrhwk
解释:
function getTimes(i) {
return new Promise(resolve => {
setTimeout(() => {
resolve(i);
}, 1000);
});
}
若要模拟 API,应使用 promise 对其进行模拟。此计时器将在超时时解析承诺。
const [heatingStepsTime, setHeatingStepsTime] = useState([]);
您希望将结果存储到一种状态中,以便 react 知道渲染结果
'0'.repeat(10).split('')
这只是为了模拟您的 for 循环...如果您有多个 API 调用,则可以忽略这一点...只需将其替换为
const promises = [apiCall1(), apiCall2()];
Promise.all(promises)
.then(result=> setHeatingStepsTime(result));
这将等待所有承诺解析并将结果存储到状态中
我找到了解决方案。在 React 中,我们需要使用 useState 在所有迭代中正确更新数组。这是固定代码 - 也许有人会遇到类似的问题,所以这里是解决方案:
import React, {useState, useEffect} from 'react';
function Ingredients() {
const [heatingStepsTime, setTime] = useState([]);
const [heatingStepsTimer, setTimer] = useState([]);
function getTimes(i, type) {
if (type === "time") {
setTimeout(() => {
setTime(currentTime => currentTime.concat(i))
},1000);
} else {
setTimeout(() => {
setTimer(currentTime => currentTime.concat(i))
}, 1000)
}
};
const getProcess = () => {
for (let i = 0; i < 3; i++) {
getTimes(i, "time");
getTimes(i, "timer");
}
}
useEffect(getProcess, []);
console.log(heatingStepsTime);
console.log(heatingStepsTimer);
if (heatingStepsTime[2] && heatingStepsTimer[2] && heatingStepsTime[2] === heatingStepsTimer[2]) {
console.log("Works!", heatingStepsTime[1], heatingStepsTimer[1])
}
return (
<div className="App">
test
</div>
);
}
export default Ingredients;