2017-01-15 9 views
0

Я пытаюсь запросить данные JSON из двух разных URL-адресов, используя fetch и отформатировать его с помощью JSX перед загрузкой в ​​объект состояния. Он извлекает данные только из одного из URL-адресов.fetch wierdness with for ... in

У меня есть 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 дважды.

Это не имеет никакого смысла для меня вообще. Я даже не догадываюсь о том, что происходит.

Я заметил, что если я ставлю заявление войти в выборку Стреле функции она показывает, что удар оба ключа и оба адреса, но если я ставлю войти заявления в конце функции в 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>

Спасибо.

ответ

1

Функции Async и для циклов - одна из больших тем в 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); 
} 

Что происходит? Вы получаете только один ключ, так что он просто будет иметь одно значение в то время, то цикл завершится до того, как функции асинхронных выполнения:

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 
} 
+0

У меня было ощущение, что это связано с тем, что асинхронные функции не выполняются до следующей итерации цикла. Я на самом деле пробовал как 'let', так и' const' на 'url',' html' и даже 'userNumber'. Я полностью забыл о 'key'. Ясно, что мое понимание работы с асинхронными функциями - небольшая неделя. Спасибо! – Vince

+0

youre welcome;) –

 Смежные вопросы

  • Нет связанных вопросов^_^