Asynchronous xmlhttp request in react

2020-06-04 07:31发布

I am trying to implement asynchronous XMLHttpRequest in react. Here is my attempt:

var xhr = new XMLHttpRequest();
var json_obj, status = false;
xhr.open("GET", "https://jsonplaceholder.typicode.com/photos/", true);
xhr.onload = function (e) {
  if (xhr.readyState === 4) {
    if (xhr.status === 200) {
      json_obj = xhr.responseText;
      status = true;
    } else {
      console.error(xhr.statusText);
    }
  }
};
xhr.onerror = function (e) {
  console.error(xhr.statusText);
};
xhr.send(null);

class Welcome extends React.Component {
  render() {
    return (
      <div>
          <img src= {status ?  json_obj[0].url : 'loading...'}></img>
      </div>
    );
  }
}
ReactDOM.render(
   <Welcome/>,
   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 thinking about adding listener to it but i don't know how to do it.

Overall i am having problem with an update after async XMLHttpRequest loads and returns value.

4条回答
唯我独甜
2楼-- · 2020-06-04 07:54

Use the component's lifecycle to load the data and then set the state asynchronously. You will also need to use JSON.parse on the data returned to you.

class Welcome extends React.Component {
  state = {}

  componentDidMount() {
    var xhr = new XMLHttpRequest();
    var json_obj, status = false;
    xhr.open("GET", "https://jsonplaceholder.typicode.com/photos/", true);
    xhr.onload = function (e) {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          var json_obj = JSON.parse(xhr.responseText);
          status = true;
          this.setState({ json_obj });
        } else {
          console.error(xhr.statusText);
        }
      }
    }.bind(this);
    xhr.onerror = function (e) {
      console.error(xhr.statusText);
    };
    xhr.send(null);
  }

  render() {
    return (
      <div>
          <img src= {this.state.json_obj ?  this.state.json_obj[0].url : 'loading...'}></img>
      </div>
    );
  }
}
ReactDOM.render(
   <Welcome/>,
   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>

查看更多
Explosion°爆炸
3楼-- · 2020-06-04 07:55

I'd recommend hooking to the componentDidMount lifecycle event and make your request there. Then, once it has finished, call setState to update the state which will re-render your component. Check out the video here if you need more info:

https://www.youtube.com/watch?v=YpM3YK9Uue0

查看更多
一夜七次
4楼-- · 2020-06-04 08:06

You need to perform the ajax request within the React lifecycle. The easiest way is to listen to componentDidMount, perform your ajax request, and then set the state.

class Welcome extends React.Component {
  constructor() {
    this.state = {
      data: null,
    };
  }

  componentDidMount() {
    var xhr = new XMLHttpRequest();
    var status = false;
    xhr.open("GET", "https://jsonplaceholder.typicode.com/photos/", true);
    xhr.onload = function (e) {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          this.setState({ data: xhr.responseText });
          status = true;
        } else {
          console.error(xhr.statusText);
        }
      }
    };
    xhr.onerror = function (e) {
      console.error(xhr.statusText);
    };
    xhr.send(null);
  }

  render() {
    if (this.state.data) {
      return <img src={this.state.data[0].url}></img>
    }
    else {
      return <div>Loading...</div>
    }
  }
}

You can read more about the component lifecycle here: https://facebook.github.io/react/docs/react-component.html

  • Note that this example doesn't handle for the fact of your component being unmounted before the XHR request finishes. Out of simplicity's sake, not including it here.
查看更多
狗以群分
5楼-- · 2020-06-04 08:07

It is recommended to make AJAX calls in the componentDidMount lifecycle method.

componentDidMount is for side effects. Adding event listeners, AJAX, mutating the DOM, etc.

Also, you should consider using the new fetch API.

class Welcome extends React.Component {
  constructor() {
    this.state = {
      data: null,
    };
  }

  componentDidMount() {
    fetch('https://jsonplaceholder.typicode.com/photos/').then(res => {
      return res.json()
    }).then(res => {
        this.setState({ data: res});
    }).catch(err);
  }

  render() {
    if (this.state.data) {
      return <img src={this.state.data[0].url}></img>
    }
    else {
      return <div>Loading...</div>
    }
  }
}
查看更多
登录 后发表回答