时间:2017-01-15 11:58:41

标签: javascript reactjs ecmascript-6 es6-promise

我尝试使用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,但在我试图弄清楚这里发生了什么时,我可能会改变它。

完整代码:

&#13;
&#13;
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;
&#13;
&#13;

谢谢。

1 个答案:

答案 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
 }