How To Fetch Data in React

How To Fetch Data in React

There are many ways to fetch data from an external API in React, but which one should you be using for your applications in 2021?

In this tutorial, we will be reviewing five of the most commonly used patterns to fetch data with React by making an HTTP request to a REST API.

We will not only cover how to fetch data, but how to best handle loading and error state upon fetching our data.

1. Using the Fetch API

The most accessible way to fetch data with React is using the Fetch API.

The Fetch API is a tool that's built into most modern browsers on the window object (window.fetch) and enables us to make HTTP requests very easily using JavaScript promises.

To make a simple GET request with fetch we just need to include the URL endpoint to which we want to make our request. We want to make this request, once our React component has mounted.

To do so, we make our request within the useEffect hook, and we make sure to provide an empty dependencies array as the second argument, so that our request is only made once (assuming it's not dependent on any other data in our component).

Within the first .then() callback, we check to see if the response was okay (response.ok). If so, we return our response to pass to the next, then call back as JSON data, since that's the data where we'll get back from our random user API.

If it's not an okay response, we assume there was an error making the request. Using fetch, we need to handle the errors ourselves, so we throw response as an error for it to handled by our catch callback.

Here in our example we are putting our error data in state with setError. If there's an error we return the text "Error!".

We use the .finally() callback as function that is called when our promise has resolved successfully or not. In it, we set loading to false, so that we no longer see our loading text.

Instead we see either our data on the page, if the request was made successfully, or that there was an error in making the request.

const data = { username: 'example' };

fetch('https://example.com/profile', {
  method: 'POST', // or 'PUT'
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => {
  console.log('Success:', data);
})
.catch((error) => {
  console.error('Error:', error);
});

2. Using Axios

The second approach to making requests with React is to use the library axios.

In this example, we will simply revise our Fetch example by first installing axios by using npm:

npm install axios

Then we will import it at the top of our component file.

What axios enables us to do is to use the exact same promise syntax as fetch, but instead of using our first then callback to manually determine whether the response is okay and throw an error, axios takes care of that for us.

Additionally, it enables us in that first callback to get the JSON data from response.data.

What's convenient about using axios is that it has a much shorter syntax that allows us to cut down on our code and it includes a lot of tools and features which Fetch does not have in its API.

All of these reasons are why it has become the go-to HTTP library for React developers.

import React from 'react';

import axios from 'axios';

export default class PersonList extends React.Component {
  state = {
    persons: []
  }

  componentDidMount() {
    axios.get(`https://jsonplaceholder.typicode.com/users`)
      .then(res => {
        const persons = res.data;
        this.setState({ persons });
      })
  }

  render() {
    return (
      <ul>
        { this.state.persons.map(person => <li>{person.name}</li>)}
      </ul>
    )
  }
}


3. Using async / await syntax

In ES7, it became possible to resolve promises using the async / await syntax.

The benefit of this is that it enables us to remove our .then(), .catch(), and .finally() callbacks and simply get back our asynchronously resolved data as if we were writing synchronous code without promises altogether.

In other words, we do not have to rely on callbacks when we use async / await with React.

We have to be aware of the fact that when we use useEffect the effect function (the first argument) cannot be made an async function.

import React, { Component } from "react";
import ReactDOM from "react-dom";

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

  async componentDidMount() {
    const response = await fetch(`https://example.com/ticker/?limit=10`);
    const json = await response.json();
    this.setState({ data: json });
  }

  render() {
    return (
      <div>
        <ul>
          {this.state.data.map(el => (
            <li>
              {el.name}: {el.price_usd}
            </li>
          ))}
        </ul>
      </div>
    );
  }
}

export default App;

ReactDOM.render(<App />, document.getElementById("app"));

As a result, instead of making that function async, we can simply create a separate async function in our component, which we can call synchronously. That is, without the await keyword before it.

4. Using a Custom React Hook (useFetch)

Over time, you may realize that it gets a bit tedious and time-consuming to keep writing the useEffect hook with all of its boilerplate within every component in which you want to fetch data.

To cut down on our reused code, we can use a custom hook as a special abstraction, which we can write ourselves get from a third party library (like we are here, using the library react-fetch-hook).

A custom hook that makes our HTTP request allows us to make our components much more concise. All we have to do is call our hook at the top of our component.

In this case, we get back all the data, loading, and error state that we need to be able to use the same structure for our component as before, but without having to useEffect . Plus, we no longer need to imperatively write how to resolve our promise from our GET request every time we want to make a request.

5. Using the library React Query

Using custom hooks is a great approach to writing much more concise HTTP requests to get our data and all of its related state, but a library that really takes data fetching with hooks to the next level is React Query.

React Query not only allows us to use custom hooks that we can reuse across our components in a concise way, but it also gives us a great deal of state management tools to be able to control when, how, and how often our data is fetched.

In particular, React query gives us a cache, which you can see below through the React Query Devtools that enables us to easily manage the requests that we have made according to key value that we specify for each request.

For the requests below, our query for our random user data is identified by the string 'random-user' (provided as the first argument to useQuery).

By referencing that key, we can do powerful things such as refetch, validate or reset our various queries.

If we rely on our custom hook solution or useEffect, we will refetch our data every single our component is mounted. To do is in most cases unnecessary. If our external state hasn't changed, we should ideally not have to show loading state every time we display our component.

React Query improves our user experience greatly by trying to serve our data from its cache first and then update the data in the background to display changes if our API state has changed.

It also gives us an arsenal of powerful tools to better manage our requests according to how our data changes through our request.

For example, if our application allowed us to add a different user, we might want to refetch that query, once the user was added. If we knew the query was being changed very frequently, we might want to specify that it should be refreshed. every minute or so. Or to be refreshed, whenever the user focuses their window tab.

In short, React Query is the go-to solution for not only making requests in a concise manner, but also efficiently and effectively managing the data that is returned for our HTTP requests across our app's components.

Cheers!

要查看或添加评论,请登录

Axel Laurent Obscura Sarzotti的更多文章

  • MAP and SET objects in Javascript

    MAP and SET objects in Javascript

    Map and Set are two JavaScript data structures you can use to store a collection of values, similar to Objects and…

    1 条评论
  • Javascript | CSS Animation Techniques

    Javascript | CSS Animation Techniques

    Animations play a vital role in enhancing user experience on web pages. They add interactivity, visual appeal, and…

  • Debugging Techniques In JavaScript

    Debugging Techniques In JavaScript

    In the field of web development, JavaScript serves as a foundational element, driving everything from simple user…

  • Context API - Redux

    Context API - Redux

    Suppose we are building an application with React and, as usually expected, passing data via props from the parent…

  • Promise.any() in Javascript

    Promise.any() in Javascript

    Promise.any(promises) is a helper function that runs promises in parallel and resolves to the value of the first…

  • React Context API with NextJS

    React Context API with NextJS

    One huge pain point in React (and NextJS) is having to pass props through multi-level components. The bigger the…

  • JavaScript CheatSheet 2021

    JavaScript CheatSheet 2021

    Cheat Sheets our something developers need always for reference. So here I have compiled many JavaScript reference…

  • Development Trends 2021

    Development Trends 2021

    Web development, over the years, has proved itself as an indispensable element in the success of any…

  • What is Redux?

    What is Redux?

    Is a light weighted State Management Tool that helps the components in our React App to communicate with each other…

  • Differences Between Arrow and Regular Functions in Javascript

    Differences Between Arrow and Regular Functions in Javascript

    In JavaScript, you can define functions in multiple ways. The first, usual way, is by using the function keyword: //…

    1 条评论

社区洞察

其他会员也浏览了