InspectorDanno
InspectorDanno

Reputation: 995

How do I handle API calls in React lifecycle methods?

I'm new to React, and trying to design an app performs a simple API call, updates the state, and conditionally renders a set of images based on the state.

I'm confused about how lifecycle methods work. According to this example, Rendering react component after api response, the API calls are supposed to be handled in componentDidMount(), and then DOM nodes based on the state are supposed to be handled in render().

However, I am confused because the React documentation says that componentDidMount() occurs after render(). So wouldn't it make sense to do the API call before the DOM nodes are rendered?

Regardless, in the example below, the default state is not being changed. handlePictures() is supposed to use the dogs api call to generate a set of pictures that will go in this.state.pictures. However, this is not happening. When I run the code on my local machine, an error occurs when I run this.createIMGs() in the render() method: it says that this.state.pictures is undefined, which leads me to guess that the API call was never made.

The API I am using is here: https://dog.ceo/dog-api/documentation/breed I am using the "multiple images from a breed collection" API, located at the bottom of the page.

//api call

const dogs = async function(breed) {
  const dogsAPI = `https://dog.ceo/api/breed/${breed}/images/random/20`;
  const dogs = await fetch(dogsAPI);
  const json = await dogs.json();
  return json.message;
}

//parent component

class DogApp extends React.Component {

  constructor() {
    super();
    this.state = {
      pictures: [],
      breed: 'hound'
    };
  }

  handleBreed(breed) {
    this.setState(() => ({
      breed
    }));
  };

  handlePictures() {
    this.setState(() => ({
      pictures: dogs(this.state.breed)
    }));
  };

  createIMGs() {
    this.state.pictures.map((picture) => ( 
      <img src={picture} alt="dog" />
    ));
  };

  componentDidMount() {
    this.handlePictures();
  }

  render() {
    return (
      this.createIMGs();
    );
  }
}

ReactDOM.render( <DogApp / > , document.getElementById('app'));
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Dogs</title>
  <link rel="icon" type="image/png" href="/images/favicon.png">
</head>

<body>
  <div id="app"></div>
</body>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
</html>

Upvotes: 0

Views: 5723

Answers (2)

Ujwal Agrawal
Ujwal Agrawal

Reputation: 474

For the answer on if API call should be made in componentDidMount() or componentWillMount() is a broad discussion topic with most of the people suggesting to making your API calls in componentDidMount().

Also, componentWillMount() method has been deprecated.

For your code not giving the desired outcome -> It is because your API call is returning a promise and to get a result from it you need to use await before it.

Note: To use await in a method, the method should be async. To do this add async before the function name.

async handlePictures() {
  const pictures = await dogs(this.state.breed);
  this.setState({
   pictures
  });
  // this.setState(() => ({
  //   pictures: dogs(this.state.breed)
  // }));
}

Here is the solution that I have uploaded on code sandbox. Have a look at it.

Edit 40jwxmwv59

Upvotes: 3

Aanchal1103
Aanchal1103

Reputation: 915

You should modify your handlePictures function to this:

async handlePictures() {
  this.setState({
    pictures: await dogs(this.state.breed)
  });
};

Because the dogs function is returning a Promise, you need to wait for it to return data.

However, I am confused because the React documentation says that componentDidMount() occurs after render(). So wouldn't it make sense to do the API call before the DOM nodes are rendered?

This has already been discussed a lot in the community. Here is an article that will help you understand why api calls are placed in componentDidMount:

https://hackernoon.com/where-to-integrate-api-calls-in-reactjs-componentwillmount-vs-componentdidmount-710085dc05c3

Upvotes: 2

Related Questions