我正在使用带有axios的React进行外部API调用,循环遍历API调用的数组中的每个对象。在内部循环中,我有一个承诺,它调用了另一个返回对象的函数。我想使用这个对象返回的值将它们分配给循环外部的变量,这是一个用于设置状态的数组,但我似乎无法这样做,因为它总是空的?希望下面代码中的注释可以帮助您理解我的问题。
let self = this;
this.instance.get('/fixtures?timeFrame=n1').then((fixtures) => {
// get all fixtures
const allFixtures = fixtures.data.fixtures;
// create valid fixtures array to add all fixture details to pass to fixtures state
let validFixtures = [];
// loop through all fixture objects in allFixtures array
for (var i = 0; i < (allFixtures.length); i++) {
// check if valid fixture, returns true or false
let isValid = self.isValid(allFixtures[i]);
// if fixture is valid
if (isValid) {
// get id of fixture to pass through to fixture route with id query
let fixtureId = allFixtures[i]._links.self.href.split('v1/')
.pop();
// home teams name
let homeTeam = allFixtures[i].homeTeamName;
// away teams name
let awayTeam = allFixtures[i].awayTeamName;
// call head2head function to get all previous results from the two teams playing and returns average score
// returns as object, example: { 'homeTeamAvgScore': 2, 'awayTeamAvgScore': 1 }
self.getHead2Head(fixtureId, homeTeam,
awayTeam).then((avg) => {
//in here i want to push object into validFixtures array along with homeTeam and awayTeam as named values
return validFixtures.push({
'homeTeam': homeTeam,
'awayTeam': awayTeam,
'homeTeamAvgScore': avg.homeTeamAvgScore,
'awayTeamAvgScore': avg.awayTeamAvgScore
})
});
}
}
//validFixtures is empty???
//How else can push to array and then later setState to fixtures with validFixtures array???
self.setState({
fixtures: validFixtures
});
}).catch((error) => {
console.log(error);
});
}
答案 0 :(得分:1)
.then
处理程序。因此,在您的情况下,validFixtures.push()
将比self.setState({ fixtures: validFixtures });
如何解决:
1)旧的JS方式。
let validFixtures = [];
let promieses = [];
for (...) {
...
promises.push(self.getHead2Head(fixtureId, homeTeam,
awayTeam).then((avg) => {
//in here i want to push object into validFixtures array along with homeTeam and awayTeam as named values
return validFixtures.push({
'homeTeam': homeTeam,
'awayTeam': awayTeam,
'homeTeamAvgScore': avg.homeTeamAvgScore,
'awayTeamAvgScore': avg.awayTeamAvgScore
})
}));
...
}
Promise.all(promises).then(() => {
self.setState({
fixtures: validFixtures
});
});
2)现代JS方式(注意async
和await
关键字):
let self = this;
this.instance.get('/fixtures?timeFrame=n1').then(async (fixtures) => {
// get all fixtures
const allFixtures = fixtures.data.fixtures;
// create valid fixtures array to add all fixture details to pass to fixtures state
let validFixtures = [];
// loop through all fixture objects in allFixtures array
for (var i = 0; i < (allFixtures.length); i++) {
// check if valid fixture, returns true or false
let isValid = self.isValid(allFixtures[i]);
// if fixture is valid
if (isValid) {
// get id of fixture to pass through to fixture route with id query
let fixtureId = allFixtures[i]._links.self.href.split('v1/')
.pop();
// home teams name
let homeTeam = allFixtures[i].homeTeamName;
// away teams name
let awayTeam = allFixtures[i].awayTeamName;
// call head2head function to get all previous results from the two teams playing and returns average score
// returns as object, example: { 'homeTeamAvgScore': 2, 'awayTeamAvgScore': 1 }
const avg = await self.getHead2Head(fixtureId, homeTeam, awayTeam);
//in here i want to push object into validFixtures array along with homeTeam and awayTeam as named values
validFixtures.push({
'homeTeam': homeTeam,
'awayTeam': awayTeam,
'homeTeamAvgScore': avg.homeTeamAvgScore,
'awayTeamAvgScore': avg.awayTeamAvgScore
});
}
}
//validFixtures is empty???
//How else can push to array and then later setState to fixtures with validFixtures array???
self.setState({
fixtures: validFixtures
});
}).catch((error) => {
console.log(error);
});
答案 1 :(得分:1)
这一特定要求被称为障碍。也就是说,您希望等待n
个任务完成,然后执行某些操作。使用屏障可以实现“等待n个任务完成”部分。
如果使用Promises,可以使用Promise.all
轻松完成。 Axios公开了承诺接口。
如果您不想使用Promises,则必须使用类似async
npm库的内容或自行实施屏障。
更新:
Async - Await
与其他答案中提到的Promise.all
不同。建议的方法会降低性能,因为循环将一个接一个地同步运行。这在MDN docs中有清楚的解释。
示例修复,
this.instance.get('/fixtures?timeFrame=n1')
.then((fixtures) => {
// ...Same code as yours
const allFixtures = fixtures.data.fixtures;
let promises = [];
for (let i = 0; i < (allFixtures.length); i++) {
// ... Same code as yours
if (isValid) {
// ... Same code as yours
// Don't call "then". We will resolve these promises later
promises.push(this.getHead2Head(fixtureId, homeTeam, awayTeam));
}
}
Promise.all(promises)
.then(averages=>{
let validFixtures = averages.map((avg, index)=>{
return {
'homeTeam': allFixtures[index].homeTeamName,
'awayTeam': allFixtures[index].awayTeamName,
'homeTeamAvgScore': avg.homeTeamAvgScore,
'awayTeamAvgScore': avg.awayTeamAvgScore
};
});
this.setState({
fixtures: validFixtures
});
});
})
.catch((error) => {
console.log(error);
});
几个侧面说明:
self
变量。只要您使用箭头函数(this
)而不是=>
关键字,function
范围就不会更改。then
结算的方式有点不同。那只是因为它对我来说似乎更具可读性