DEV Community

loading...

Fetching Data in React Applications

Linas Spukas
Full-stack web developer with a specialisation in React and NodeJS.
・3 min read

React is a library for building and handling user interface and is not responsible for fetching data. To make network or Ajax requests and load some information, we have to create a service, separate piece of code that will handle such requests. In this post, I will discuss how and where we can make requests within a React application.

How to Load Resources

To make HTTP requests we have a couple good options. One is a Fetch, a Web API that is supported by all (excluding IE) browsers natively. Another option is a third-party library, for example axios.
Both options have advantages and disadvantages. Let's take a close look at each of them.

Fetch API is a promise based Request and Response service. As it is supported by browsers, you can test it in your browser console.

  fetch("https://reqres.in/api/users/1")
    .then(response => response.json())
    .then(json => console.log(json));

It is slim, easy to use untill fetching requirements are minimal and does not require much configuration.

Pros:

  • have basic functionality for Request and Response objects
  • no need to install a third-party library (no dependencies)

Cons:

  • will not reject on HTTP error status, always resolves with ok status
  • will not receive cross-site cookies
  • you'll end up writing more code

Axios library is a prevalent HTTP client with much more extended functionality. It is very well documented, easy to use and gives an excellent development experience.

const axios = require('axios');

axios.get("https://reqres.in/api/users/1")
  .then(response => console.log(response)) // auto transform to JSON
  .catch(error => console.log(error)); // error handling

Pros:

  • the browser and node.js support
  • cancel requests
  • handles rejections
  • support Promises
  • supporting protection against XSRF
  • older browser support

Cons:

  • an extra dependency that needs to be loaded from an external source
  • consumes more client/server resources
  • includes features you will probably never use

For the most basic use cases on the client-side most of use probably can get with the native Fetch API.

Where to Load

In a React application, usually, requests are made on two occasions. First, as soon as the page loads, and the second is initiated by user interaction (search, submit).
To load resources as soon as the page loads, the data fetching must happen in componendDidMount() lifecycle method (for class components), or useEffect() hook (functional components).

Following example illustrates data fetching on the page load. First, we create an async data fetching function. Inside it, we call fetch() method to get recourses from API. In return, we receive a Promise and need to wait for it to resolve and transform data into JSON format. Then data can be saved to the components state.
To make sure the function runs once, we pass an empty dependency array as a second argument to useEffect().

function App() {
  const [users, setUsers] = React.useState([]);

  React.useEffect(() => {
    fetchUsers();
  }, []);

  async function fetchUsers() {
    const response = await fetch("https://reqres.in/api/users");
    const json = await response.json();

    setUsers([...users, ...json.data]);
  }

  return users.map(user => <li key={user.id}>{user.first_name}</li>);
}

If you need to load data only when the user explicitly asks for it through the interactions, like button clicks, then we do not need to use effect hook. The function can be called in a simple event handler:

function App() {
  const [users, setUsers] = React.useState([]);

  async function fetchUsers() {
    const response = await fetch("https://reqres.in/api/users");
    const json = await response.json();

    setUsers([...users, ...json.data]);
  }

  function handleClick() {
    fetchUsers();
  }

  return (
    <div>
      <button onClick={handleClick}>Load users</button>
      {users.map(user => <li key={user.id}>{user.first_name}</li>)}
    </div>
  );
}

And we can combine both methods. Load initial list of users on page render in useEffect(), and add to list more content by pressing the button. Only this time we add a page count as a second state to load different data from API. Adding a page state as a dependency to useEffect() we will trigger the function inside it to run when we increment the page count:

function App() {
  const [users, setUsers] = React.useState([]);
  const [page, setPage] = React.useState(1);

  React.useEffect(() => {
    fetchUsers()
  }, [page]);

  async function fetchUsers() {
    const response = await fetch(`https://reqres.in/api/users/${page}`);
    const json = await response.json();

    setUsers([...users, ...json.data]);
  }

  function handleClick() {
    setPage(page + 1);
  }

  return (
    <div>
      <button onClick={handleClick}>Load more</button>
      {users.map(user => <li key={user.id}>{user.first_name}</li>)}
    </div>
  );
}

To make the code more extendable and readable must be cleaned a little bit. API related configuration should be moved into separate function or a custom hook.
And that's about it, these examples should cover basic cases for data fetching and storing in a React application, but leave a comment if I missed something to add.

Discussion (0)