2017-01-15 7 views
0

Ich versuche, JSON-Daten von zwei verschiedenen URLs mit fetch anzufordern und formatieren sie mit JSX vor dem Laden in das Statusobjekt. Es ruft nur die Daten von einer der URLs ab.fetch wierdness mit für ... in

I haben die URLs in einem Objekt wie folgt aus:

var urls = { 
    'recent': 'https://fcctop100.herokuapp.com/api/fccusers/top/recent', 
    'alltime': 'https://fcctop100.herokuapp.com/api/fccusers/top/alltime', 
}; 

I um die Daten holen will, indem über das Objekt Iterieren die URLs, machen es zu einem Array von JSX Objekte enthält, dann speichere das Ergebnis in der Zustand meines Hauptobjekts.

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. 
} 

Es soll die Daten aus der recent URL holen und in this.state.data.recent das formatierte Ergebnis speichern. Dann sollte es dasselbe für alltime tun, das Ergebnis in this.state.data.alltime speichernd. Was es tatsächlich zu tun scheint, ist, alltime zweimal zu holen.

Das macht für mich überhaupt keinen Sinn. Ich habe keine Ahnung, was passiert.

Ich habe bemerkt, dass, wenn ich Aussagen identisch log in die Funktion Pfeil holen es zeigt, dass es die beiden Tasten und die beiden URLs ist schlagen, aber wenn ich Aussagen setzen log am Ende der response.json() Pfeil Funktion nach json.map, zeigt es alltime zweimal .

Es verarbeitet die zweite URL zweimal. Ich weiß, dass die Reihenfolge nicht garantiert ist, aber es neigt dazu, sie in der Reihenfolge zu verarbeiten, in der ich sie definiert habe, und ich denke, das ist hier von Bedeutung. Selbst wenn es sich um asynchrone Anfragen handelt, die gleichzeitig auftreten, handelt es sich doch um zwei verschiedene Anfragen, die Daten an zwei verschiedenen Orten speichern, nicht wahr?

Eine Version dieses Codes ist auch at CodePen, aber ich werde das wahrscheinlich ändern, während ich versuche, herauszufinden, was hier vor sich geht.

Voll Code:

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>

Danke.

Antwort

1

Async-Funktionen und for-Schleifen sind eines der großen Themen in js (kann sie auf SO suchen). Sie können mit Hilfe eines IIFE oder lassen gelöst werden:

for(let key in keys){ 
    //your code, key will be locally scoped 
} 

oder:

for(key in keys){ 
(function(key){ 
    //key is locally scoped 
})(key); 
} 

Was passiert? Youve bekam nur einen Schlüssel, so wird es nur einen Wert zu einer Zeit, die für die Schleife wird beendet, bevor die Asynchron-Funktionen ausführen:

key="recent"; 
key="alltime"; 
//async functions run 

Warum lokale Bedeutung hat (Block) Scoping hilft? Gut:

+0

Ich hatte das Gefühl, dies hatte etwas mit den asynchronen Funktionen zu tun, die nicht vor der nächsten Iteration der Schleife abgeschlossen. Ich probierte sowohl 'Let' als auch' const' auf 'url',' html' und sogar 'userNumber'. Ich habe 'Schlüssel' komplett vergessen. Offensichtlich ist mein Verständnis der Arbeit mit asynchronen Funktionen eine kleine Woche. Vielen Dank! – Vince

+0

sind herzlich willkommen;) –