我正在尝试使用 fetch 从两个不同的 URL 请求 JSON 数据并在将其加载到状态对象之前使用 JSX 对其进行格式化。它仅从其中一个 URL 检索数据。
我的对象中有这样的 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
中。它实际上所做的似乎是 fetch alltime
两次。
这对我来说完全没有意义。我什至不知道发生了什么。
我注意到,如果我将日志语句放入 fetch 的箭头函数中,它会显示它同时命中了两个键和两个 URL,但是如果我将日志语句放在 response.json()
的末尾,箭头函数,json.map
之后,它显示alltime
两次。
它正在处理第二个 URL 两次。我知道顺序不能保证,但它确实倾向于按照我定义它们的顺序处理它们,我认为这在这里很重要。即使这是同时发生的异步请求的问题,但它们是两个不同的请求,最终将数据存储在两个不同的位置,不是吗?
此代码的一个版本也是 at CodePen ,但当我试图弄清楚这里发生了什么时,我可能会改变它。
完整代码:
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'));
img {
width: 2em;
height: 2em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<main id="app"></main>
最佳答案
异步函数和for循环是js中的大话题之一(可以在SO上搜索它们)。它们可以使用 IIFE 或 let 来解决:
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
为什么本地( block )作用域有帮助?嗯:
{
key="recent";
//async function one fires, key is recent
}
{
key="alltime";
//async function two fires, key is alltime
}
关于javascript - 在 JavaScript 中使用 for...in 获取奇怪的东西,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41660830/