React AJAX: creating HTTP requests with React and AJAX

Posted on October 22, 2020


One of the most asked questions by people learning React is:

How do I code an AJAX call in React?

This is a valid question because modern web-based applications tend to have a modular architecture, where the back-end is separated from the front-end. The front-end app will need to access data from a remote endpoint or server.

But here’s the interesting point: React doesn’t tell you how you should send your AJAX calls. The library only focuses on rendering UI with data from state and props. This means you can use any AJAX-based libraries to fetch your data.

Some of the most popular libraries include:

These HTTP request libraries have a slight of different features, but it really doesn’t matter which one you choose.

Once you’ve chosen a library to use with your project, let’s learn about when you should make an HTTP request.

Make AJAX calls when the component has been mounted

AJAX calls in React should be done right after your component has been rendered into the browser for the first time. This is so you can update your state when the data has been retrieved from the endpoint.

If you write components using the class approach, you place your AJAX request in componentDidMount() lifecycle function. When the data is retrieved, you will need to assign it to state with setState function.

Here’s an example of fetching GitHub users data from its API. Notice how the code is written inside componentDidMount() function:

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

  componentDidMount() {
    fetch("https://api.github.com/users?per_page=3")
      .then((res) => res.json())
      .then(
        (data) => {
          this.setState({
            data: data
          });
        },
        (error) => {
          console.log(error)
        }
      );
  }

  render() {
    const { data } = this.state;
    return (
      <div className="App">
        <h1>React AJAX call</h1>
        <ul>
          {data.map((item) => (
            <li key={item.id}>{item.login}</li>
          ))}
        </ul>
      </div>
    );
  }
}

When you use the function approach, you place the request inside useEffect() hook with an empty array [] as its second parameter, so that the hook will run only once at first render.

The code below is the same as the above:

import React, { useState, useEffect } from "react";

export default function App() {
  const [data, setData] = useState([]);

  useEffect(() => {
    fetch("https://api.github.com/users?per_page=3")
      .then((res) => res.json())
      .then(
        (data) => {
          setData(data);
        },
        (error) => {
          console.log(error);
        }
      );
  }, []);

  return (
    <div className="App">
      <h1>React AJAX call</h1>
      <ul>
        {data.map((item) => (
          <li key={item.id}>{item.login}</li>
        ))}
      </ul>
    </div>
  );
}

While React will execute both examples above without any errors, you might notice that there’s a slight delay before React renders the data that you’re fetching from the remote endpoint. You can clarify this by adding a delay before your AJAX call is executed:

componentDidMount() {
  setTimeout(() => {
    fetch("https://api.github.com/users?per_page=3")
      .then((res) => res.json())
      .then(
        (data) => {
          this.setState({
            data: data
          });
        },
        (error) => {
          console.log(error);
        }
      );
  }, 5000);
}

You can do the same with the function component:

useEffect(() => {
  setTimeout(() => {
    fetch("https://api.github.com/users?per_page=3")
      .then((res) => res.json())
      .then(
        (data) => {
          setData(data);
        },
        (error) => {
          console.log(error);
        }
      );
  }, 5000);
}, []);

It will be so much better when the application can tell your users that the data is still being retrieved. You can do this by adding a state that returns true when the data is loading and false when the data has finished loading. Notice how isLoading state is added in the following example:

import React, { useState, useEffect } from "react";

export default function App() {
  const [data, setData] = useState([]);
  const [isLoading, setLoading] = useState(true);

  useEffect(() => {
    fetch("https://api.github.com/users?per_page=3")
      .then((res) => res.json())
      .then(
        (data) => {
          setData(data);
          setLoading(false);
        },
        (error) => {
          console.log(error);
          setLoading(false);
        }
      );
  }, []);

  if (isLoading) {
    return <h1>Loading data... </h1>;
  } else {
    return (
      <div>
        <h1>React AJAX call</h1>
        <ul>
          {data.map((item) => (
            <li key={item.id}>{item.login}</li>
          ))}
        </ul>
      </div>
    );
  }
}

Finally, you can also render an error message when your AJAX call returns an error. You just need to add another state for storing the error:

import React, { useState, useEffect } from "react";

export default function App() {
  const [data, setData] = useState([]);
  const [isLoading, setLoading] = useState(true);
  const [error, setError] = useState(false);

  useEffect(() => {
    fetch("https://api.github.com/users?per_page=3")
      .then((res) => res.json())
      .then(
        (data) => {
          setData(data);
          setLoading(false);
        },
        (error) => {
          setError(error);
          setLoading(false);
        }
      );
  }, []);

  if (error) {
    return <div>Fetch request error: {error.message}</div>;
  } else if (isLoading) {
    return <h1>Loading data... </h1>;
  } else {
    return (
      <div>
        <h1>React AJAX call</h1>
        <ul>
          {data.map((item) => (
            <li key={item.id}>{item.login}</li>
          ))}
        </ul>
      </div>
    );
  }
}

See a working codesandbox example here.

I will leave out the class component example for you to try on your own.

Conclusion

As you can see in the examples above, React is a library that focuses on rendering user interface to the browser through components. It doesn’t even have a mechanism to create a request.

The way to make AJAX calls (or HTTP API requests) in React is to put your own request code into the componentDidMount() function or creating a useEffect() hook that gets executed only once after the component has been rendered to the browser.

Related articles:

Level up your React skill today 🔥

Build FOUR projects using React with my latest book.

Structured knowledge from beginner to experienced level!

Learn more