mizech mizech - 1 year ago 67
Javascript Question

React : How to make sure that requested data are available before rendering?

I'm trying to make a weather widget with React.

The data used I get from OpenWeatherMap:

My problem was (or is) that the render function is called at once. But the requested data from the OpenWeatherMap API aren't available yet. So the interpreter throws an error because props are accessed which aren't defined (yet).

I have found a workaround by putting the return statement of the render function into an if-else:

var React = require('react');
var DayInfos = require('./DayInfos.jsx');
var MainInfoPanel = require('./MainInfoPanel.jsx');

var WeatherApp = React.createClass({
getInitialState: function() {
return {
data: null
componentWillMount: function() { // Call before the initial rendering
var apiData = new Promise(function(resolve, reject) {
var request = new XMLHttpRequest();

request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200) {
} else {
reject('HTTP request on openweathermap has failed.');

request.open('get', 'http://api.openweathermap.org/data/2.5/forecast?q=London,us&mode=json&appid=efcd313fa7a139f2fb20de306648eb8d');

apiData.then(function(weatherData) {
data: JSON.parse(weatherData)
}.bind(this), function(message) {
render: function() {
if (this.state.data) { // Make sure the data is available.
return (
<div className="weather-app" >
<MainInfoPanel city={ this.state.data.city } today={ this.state.data.list[0] } />
<DayInfos />
<DayInfos />
<DayInfos />
<DayInfos />
} else {
return null;

module.exports = WeatherApp;

I works now but I'm not sure if I handle the issue in a proper way.

Actually I thought the used function componentWillMount ( https://facebook.github.io/react/docs/component-specs.html#mounting-componentwillmount ) would take care for the issue. But obviously it just triggers the request. The rest runs further without waiting for the data to arrive.

Therefore my question to the more experienced React-developers:

How can one delay the initial rendering until the requested data are available?


What is a proper strategy to avoid a crashing application because of lacking data?

Answer Source

I usually use a spinner to indicate that the widget is loading:

render() {
    return this.state.loading ? (
      <div className="spinner">
        <Spinner />
    ) : this.renderView();

renderView() does the actual rendering when state.loading is false. When state.loading is true, a spinner is displayed.

In componentWillMount, I set loading to true before making the API call.

componentWillMount() {
    this.setState({loading: true});
    ajaxCall().then(responses => {
      // process response
      this.setState({loading: false});
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download