Andrew Zaw
Andrew Zaw

Reputation: 814

Getting React to re-render after Promise is completed

I've simplified much of the code as the issue lies in the Promise and async/await part.

I wish for this component to get data from my API and create a plot from it. If the API is still retrieving, I want it to show the loading icon.

class Data extends Component {
  state = {};

  componentDidMount() {
    this.setState({ data: this.getData() });
  }

  async getData() {
    try {
      const response = await axios.get('/api/data');
      return response.data;
    } catch (err) {
      return [];
    }
  }

  renderLoading() {
    return <Loading/>; // this represents a loading icon
  }

  renderPlot(data) {
    return <Plot data={data}/>; // this represents the plot that needs the data
  }

  render() {
    return {this.state.data
          ? this.renderLoading()
          : this.renderPlot(this.state.data)};

  }
}

At the moment, what this does is check this.state.data, sees that it's undefined, and simply display the loading icon forever without ever checking it again. How can I make it recheck once the promise is completed? One issue to note is that renderPlot requires data to be finished, if I call renderPlot while the Promise is still pending, it doesn't process it properly.

Upvotes: 2

Views: 4882

Answers (2)

coreyward
coreyward

Reputation: 80041

Instead of calling setState before the data is ready, call this.getData() in componentDidMount and then call setState once the response data is ready. React will automatically re-render the component with state changes.

class Data extends Component {
  state = {}

  componentDidMount() {
    this.getData()
  }

  getData() {
    axios
      .get('/api/data')
      .then(({ data }) => {
        this.setState({ data })
      })
      .catch(err => {
        this.setState({ error: err.message })
      })
  }

  render() {
    return this.state.data
          ? <Plot data={this.state.data} />
          : this.state.error
          ? <div>{this.state.error}</div>
          : <Loading />
  }
}

Upvotes: 7

Patrick
Patrick

Reputation: 6948

You need to call setState after your async operation completes. Try this in your componentDidMount()

componentDidMount() {
    // Wait for the operation to complete before setting data
    this.getData().then((d) => {
        this.setState({ data: d});
    });
}

Your code just sets data to be the Promise of the async operation.

Upvotes: 1

Related Questions