我尝试使用fetch从两个不同的URL请求JSON数据,并在将其加载到状态对象之前使用JSX对其进行格式化。它只从其中一个网址中检索数据。
我在这样的对象中有URL:
var urls = {
'recent': 'https://fcctop100.herokuapp.com/api/fccusers/top/recent',
'alltime': 'https://fcctop100.herokuapp.com/api/fccusers/top/alltime',
};
我想通过迭代包含URL的对象来获取数据,将其转换为JSX对象数组,然后将结果存储在主对象的状态中。
for (var key in urls) {
var url = urls[key];
fetch(url).then((response) => {
response.json().then((json) => {
var userNumber = 0;
var html = json.map((user) => {
return (
<tr>
<td>{++userNumber}</td>
<td>
<img src={user.img} alt={user.username} />
{user.username}
</td>
<td>{user.recent}</td>
<td>{user.alltime}</td>
</tr>
);
}); // Close json.map block.
this.setState({
'data': { [key]: html }
});
console.log(key);
}); // Close response.json block.
}); // Close fetch block.
}
它应该从recent
URL获取数据并将格式化结果存储在this.state.data.recent
中。然后它应该为alltime
执行相同的操作,将结果存储在this.state.data.alltime
中。它实际上做的是两次获取alltime
。
这对我来说毫无意义。我甚至不知道发生了什么。
我注意到如果我将日志语句放入fetch的箭头函数中,它会显示它同时击中了两个键和两个URL,但是如果我将日志语句放在{{1}的末尾箭头功能,在response.json()
之后,它会显示json.map
两次。
它处理第二个URL两次。我知道订单没有保证,但它确实倾向于按照我定义它们的顺序处理它们,我认为这里有重要意义。即使同时发生异步请求是一个问题,他们还有两个不同的请求,最终将数据存储在两个不同的地方,不是吗?
此代码的版本也是at CodePen,但在我试图弄清楚这里发生了什么时,我可能会改变它。
完整代码:
alltime
&#13;
var urls = {
'recent': 'https://fcctop100.herokuapp.com/api/fccusers/top/recent',
'alltime': 'https://fcctop100.herokuapp.com/api/fccusers/top/alltime',
};
function View(props) {
return (
<form className="view">
<label>View: </label>
<label><input type="radio" name="view" value="recent" checked={props.view == 'recent'} />Past 30 Days</label>
<label><input type="radio" name="view" value="alltime" checked={props.view == 'alltime'} />All Time</label>
</form>
);
}
class Main extends React.Component {
constructor() {
super();
this.state = {
'view': 'recent',
'data': {
'recent': null,
'alltime': null,
},
};
}
componentWillMount() {
for (var key in urls) {
var url = urls[key];
console.log(key);
console.log(url);
fetch(url).then((response) => {
response.json().then((json) => {
var userNumber = 0;
var html = json.map((user) => {
return (
<tr>
<td>{++userNumber}</td>
<td>
<img src={user.img} alt={user.username} />
{user.username}
</td>
<td>{user.recent}</td>
<td>{user.alltime}</td>
</tr>
);
}); // Close json.map block.
console.log('Setting state for ' + key);
this.setState({
'data': { [key]: html }
});
}); // Close response.json block.
}); // Close fetch block.
}
/*
fetch(urls.recent).then((response) => {
response.json().then((json) => {
var view = 'recent';
var html = json.map((user) => {
return (
<tr>
<td>
<img src={user.img} alt={user.username} />
{user.username}
</td>
<td>{user.recent}</td>
<td>{user.alltime}</td>
</tr>
);
}); // Close json.map block.
this.setState({
'data': { [view]: html },
});
}); // Close response.json block.
}); // Close fetch block.
*/
}
render() {
return (
<div>
<View view={this.state.view} />
<table>
{this.state.data[this.state.view]}
</table>
</div>
);
}
}
ReactDOM.render(<Main />, document.getElementById('app'));
&#13;
img {
width: 2em;
height: 2em;
}
&#13;
谢谢。
答案 0 :(得分:1)
异步函数和for循环是js中的一个重要主题(可以在SO上搜索它们)。它们可以使用IIFE解决或让:
for(let key in keys){
//your code, key will be locally scoped
}
或:
for(key in keys){
(function(key){
//key is locally scoped
})(key);
}
会发生什么?你只有一个键,所以它一次只有一个值,for循环将在异步函数执行之前完成:
key="recent";
key="alltime";
//async functions run
为什么本地(块)范围有帮助?良好:
{
key="recent";
//async function one fires, key is recent
}
{
key="alltime";
//async function two fires, key is alltime
}