0

I did an example of multi async XMLHttpReqest based on examples i found:

var  URL=["https://api.github.com/users/github","https://api.github.com/users/github/repos"];
var xhr = [null, null];
for (var i = 0; i < 2; i++) {
  (function(i) {
xhr[i] = new XMLHttpRequest();
xhr[i].open("GET", URL[i], true);
xhr[i].onload = function (e) {
  if (xhr[i].readyState === 4) {
    if (xhr[i].status === 200) {
      console.log(xhr[i].responseText);
    } else {
      console.error(xhr[i].statusText);
    }
  }
};
xhr[i].onerror = function (e) {
  console.error(xhr[i].statusText);
};
xhr[i].send(null);
  })(i);
}

Thing is that i am having a problem with implementing it in react as i can not assign value with this.setState({json_objs[i]:JSON.parse(xhr[i].responseText}) to object array.

This is my react code which is not working due problems with assigning value:

import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';




class ImageViewer extends React.Component {
    constructor() {
        super();
        this.state = {
            json_objs : [null,null],
            links:["https://api.github.com/users/github/repos","https://api.github.com/users/github"]
   
        }
    }
 componentDidMount() {
    var xhr = [null, null]
    for (var i = 0; i < 2; i++) {
    (function(i) {
  xhr[i] = new XMLHttpRequest();
  xhr[i].open("GET", this.state.link, true);
  xhr[i].onload = function (e) {
   if (xhr[i].readyState === 4) {
    if (xhr[i].status === 200) {
     this.setState({ json_objs[i]:JSON.parse(xhr[i].responseText)});
    } else {
    console.error(xhr[i].statusText);
    }
   }
  }.bind(this);
  xhr[i].onerror = function (e) {
  console.error(xhr[i].statusText);
  };
  xhr[i].send(null);
      })(i);
}

   render() {
           if (!this.state.json_objs[0] || !this.state.json_objs[1]) {
    return <div>Loading...</div>;
  }
  return(
<div>
<div><h1>{this.state.json_objs[1].email}</h1></div>
       {this.state.json_objs[0].sort(function(a, b){var keyA = new Date(a.updated_at),keyB = new Date(b.updated_at);if(keyA > keyB) return -1;if(keyA < keyB) return 1;return 0;}).map((obj, index)  => {
                            return (
         <div key={index}>
         <div>{obj.name}</div>
         <div>{(new Date(obj.updated_at)).toString()}</td>
        </div>
                            )
                    })}
</div>
    )
}}
ReactDOM.render(<ImageViewer />, document.getElementById('root'));
<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>
<div id="root"></div>

I have been reading about modyfing arrays in react but i am having problems with implementing it.

Mac
  • 307
  • 3
  • 8
  • 18
  • `{ json_objs[i]:JSON.parse(xhr[i].responseText)}` is not valid javascript syntax, I expect you get some error in the console about this? – Jaromanda X Aug 21 '17 at 00:37
  • yes, i am getting errors due this. It was just to show what i am trying to do. – Mac Aug 21 '17 at 00:38
  • but it doesn't really explain what you want very well - what do you expect the `key` for that property to actually be – Jaromanda X Aug 21 '17 at 00:39
  • { json_objs[i]:JSON.parse(xhr[i].responseText)} an i just like you posted. It will be like in loop 0 and 1. – Mac Aug 21 '17 at 00:40
  • that's not valid syntax ... you are calling setState with an object that has a single property ... what is the value of the key that you want (what you've written as the invalid `json_objs[i]`) ... e.g. `{fred:JSON.parse(xhr[i].responseText)}` or `{wilma:JSON.parse(xhr[i].responseText)}` are valid, but your code is still invalid in the question and in the comment ... is `json_obs` an array of strings perhaps? no, it's an array of nulls, so there's no information in your continued use of `{{fred:JSON.parse(xhr[i].responseText)}` – Jaromanda X Aug 21 '17 at 00:41
  • 1
    AHH!!! I see what you're trying to do ... you're trying to populate json_objs[i] with the result – Jaromanda X Aug 21 '17 at 00:45
  • I see. I need to get all repository names and dates "updated_at" from the first one and login and email from the 2nd one. – Mac Aug 21 '17 at 00:46
  • Yes, i am trying to populate json_objs[i] with results. – Mac Aug 21 '17 at 00:46
  • you'll also find that `this` in `this.setState` is not the `this` you expect ... `this` will be the XHR object – Jaromanda X Aug 21 '17 at 00:46
  • 1
    Why not simply use axios? – Gerardo Aug 21 '17 at 00:50
  • Do you need to setState for each XHR, or is the point of the question that you want to wait until both XHR are complete, and then you setState? – Jaromanda X Aug 21 '17 at 00:51
  • I want to wait until both XHR are complete and set the state. – Mac Aug 21 '17 at 00:51
  • 1
    Rob's answer is good then :p – Jaromanda X Aug 21 '17 at 00:54
  • How can i assign values as i wanted to each object of the array json_objs? – Mac Aug 21 '17 at 01:27

1 Answers1

2

I think Promise's would be helpful here. Wrap each XHR request in a Promise, use Promise.all() to wait for both of them complete, then set your results into state (it will resolve with an array of response objects):

Promise.all([0, 1].map((index) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open("GET", this.state.links[index], true)
    xhr.onload = function() {
      if (xhr.readyState === 4) {
        if(xhr.status === 200) {
          resolve(JSON.parse(xhr.responseText))
        } else {
          reject(xhr.statusText)
        }
    }
  })
})).then((json_objs) => {
  this.setState({ json_objs }, () => {
     console.log('json_objs => ', this.state.json_objs)
  })
}).catch(err => console.error(err))
Rob M.
  • 35,491
  • 6
  • 51
  • 50