what is right way to do API call in react js?

Solution 1:

In this case, you can do ajax call inside componentDidMount, and then update state

export default class UserList extends React.Component {
  constructor(props) {
    super(props);

    this.state = {person: []};
  }

  componentDidMount() {
    this.UserList();
  }

  UserList() {
    $.getJSON('https://randomuser.me/api/')
      .then(({ results }) => this.setState({ person: results }));
  }

  render() {
    const persons = this.state.person.map((item, i) => (
      <div>
        <h1>{ item.name.first }</h1>
        <span>{ item.cell }, { item.email }</span>
      </div>
    ));

    return (
      <div id="layout-content" className="layout-content-wrapper">
        <div className="panel-list">{ persons }</div>
      </div>
    );
  }
}

Solution 2:

You may want to check out the Flux Architecture. I also recommend checking out React-Redux Implementation. Put your api calls in your actions. It is much more cleaner than putting it all in the component.

Actions are sort of helper methods that you can call to change your application state or do api calls.

Solution 3:

Use fetch method inside componentDidMount to update state:

componentDidMount(){
  fetch('https://randomuser.me/api/')
      .then(({ results }) => this.setState({ person: results }));
}

Solution 4:

This discussion has been for a while and @Alexander T.'s answer provided a good guide to follow for newer of React like me. And I'm going to share some additional know-how about calling the same API multiple times to refresh the component, I think it's probably a common question for beginners.

componentWillReceiveProps(nextProps), from official documentation :

If you need to update the state in response to prop changes (for example, to reset it), you may compare this.props and nextProps and perform state transitions using this.setState() in this method.

We could conclude that here is the place we handle props from the parent component, have API calls, and update the state.

Base on @Alexander T.'s example:

export default class UserList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {person: []};
  }

  componentDidMount() {
   //For our first load. 
   this.UserList(this.props.group); //maybe something like "groupOne"
  }

  componentWillReceiveProps(nextProps) {
    // Assuming parameter comes from url.
    // let group = window.location.toString().split("/")[*indexParameterLocated*];
    // this.UserList(group);
   
    // Assuming parameter comes from props that from parent component.
    let group = nextProps.group; // Maybe something like "groupTwo" 
    this.UserList(group);
  }

  UserList(group) {
    $.getJSON('https://randomuser.me/api/' + group)
      .then(({ results }) => this.setState({ person: results }));
  }

  render() {
    return (...)
  }
}

Update

componentWillReceiveProps() will be deprecated.

Here are only some methods (all of them in Doc) in the life cycle I think that they are related to deploying API in the general cases: enter image description here

By referring to the diagram above:

  • Deploy API in componentDidMount()

    The proper scenario to have API call here is that the content (from the response of API) of this component will be static, componentDidMount() only fire once while the component is mounting, even new props are passed from the parent component or have actions to lead re-rendering.
    The component do check difference to re-render but not re-mount.
    Quote from doc:

If you need to load data from a remote endpoint, this is a good place to instantiate the network request.


  • Deploy API in static getDerivedStateFromProps(nextProps, prevState)

We should notice that there are two kinds of component updating, setState() in current component would not trigger this method but re-rendering or new props from parent component would. We could find out this method also fires while mounting.

This is a proper place to deploy API if we want to use the current component as a template, and the new parameters to make API calls are props coming from parent component.
We receive a different response from API and return a new state here to change the content of this component.

For example:
We have a dropdown list for different Cars in the parent component, this component needs to show the details of the selected one.


  • Deploy API in componentDidUpdate(prevProps, prevState)

Different from static getDerivedStateFromProps(), this method is invoked immediately after every rendering except the initial rendering. We could have API calling and render difference in one component.

Extend the previous example:
The component to show Car's details may contain a list of series of this car, if we want to check the 2013 production one, we may click or select or ... the list item to lead a first setState() to reflect this behavior (such as highlighting the list item) in this component, and in the following componentDidUpdate() we send our request with new parameters (state). After getting the response, we setState() again for rendering the different content of the Car details. To prevent the following componentDidUpdate() from causing the infinity loop, we need to compare the state by utilizing prevState at the beginning of this method to decide if we send the API and render the new content.

This method really could be utilized just like static getDerivedStateFromProps() with props, but need to handle the changes of props by utilizing prevProps. And we need to cooperate with componentDidMount() to handle the initial API call.

Quote from doc:

... This is also a good place to do network requests as long as you compare the current props to previous props ...