Obsessed with React and teaching. I help people become Frontend Developers. Living with my fiancee and Yorkshire Terrier 🐶 in Poland.
Obsessed with React and teaching. I help people become Frontend Developers. Living with my fiancee and Yorkshire Terrier 🐶 in Poland.

How To Fetch Data In React From REST API

Jan 30, 2021
20 min read

DESCRIPTION

Let's learn how to fetch data in React using fetch, axios, and react-query. We'll create a custom useApi hook and build a simple Pokemon application using pokeAPI.

Introduction

In this article, we'll build a Pokemon application using PokeAPI and Material UI GridList component. To do that, I'll guide you through how to fetch data in React with hooks.
Function components in React are great but data fetching with them can be cumbersome at first. When I moved to using hooks it took me some time to grasp what's going on. If you're starting out, check out Hooks introduction from the official documentation. Additionally, read about useState and useEffect hooks as we'll need them.
I'll start from using fetch to get the data from PokeAPI, then refactor the code for using a custom useApi hook with axios, and end up with react-query as it's an amazing library.
In the end, you should have a fair understanding of hooks, data fetching in React and build the below Pokemon list application. 😎
Important: React devs are working on Suspense API and server-side components, both of these exciting features can impact the ideology behind data fetching - still, hooks are instrumental to understand all of these concepts and I highly encourage you to dive into this article.

Fetch PokeAPI data with hooks

Let's start from the mentioned fetch, we'll use it with async/await syntax. It's pretty much a syntatic sugar built on top of promises.
Note: I'm using a codesandbox to develop this application but you could set up a local repository with e.g. CRA or any favorite boilerplate you want.

Fetching data is not so straightforward

First, we're setting the initial pokemons state variable to [] (empty array) using the useState hook. Then, using useEffect hook and fetch with async/await (please, notice the usage of .json() to get an actual JSON from HTTP response), we get the data from pokeAPI, limiting it to the first 100 Pokemons. After that, we save data.results using setPokemons function. In the end, we return a simple JSX to render the list of Pokemon names.
However, we end up in an infinity loop. useEffect hook runs when the component mounts and when it updates. We're setting the data of Pokemons after we receive it from the fetch which updates the state and triggers useEffect to run again.
To prevent that, we need to add an empty list of dependencies to useEffect hook, then it'll run only once - when the component mounts. And that's what we need.
No more infinity loop. 🎉 But still, when I run the above code in the sandbox environment, we get this warning: "Effect callbacks are synchronous to prevent race conditions. Put the async function inside". async/await returns a promise but useEffect should return either nothing or a cleanup function. Let's fix that.
Thanks to our fetchData function inside of the useEffect hook, we got rid of the warning. 🎉
If you'd like to get the data when a user types something in the search field (e.g. to find a particular Pokemon), you can pass additional dependencies to the [] dependency list on useEffect. This will be a bit problematic as each time the user types in, useEffect will fetch the data. You'll need to use some debounce technique to solve it.
If you need to get the data on button click, create an async. function and assign it to the onClick event.
The above solutions are out of the scope of this guide. I covered them in a separate article as there are not too many "out of the box" resources to explain these topics.

What about error handling and loading state?

In a real-world project, you can't let the application crash when something goes wrong. There should be a gently alert to the user which is often called a fallback UI. We won't use React ErrorBoundary for this project for simplicity reasons but instead, we'll handle the error inside of the component directly using the Alert component.
For loading, we'll show a spinner component when data is still being fetched using the CircularProgress and Grid components.
We've added state responsible for error and loading, introduced try...catch to make sure we catch all the possible states. When the error happens, we'll show the Alert component with an error message.
Loading is a bit more tricky as we set a default value to true. It was intended as we don't want to render an empty page when there is no data yet. Instead, CircularProgress will show up.
Everything is almost perfect but we're mixing logic with rendering in one component. You're guessing right, it's time to create our custom useApi hook component and refactor the code a little bit.

useApi hook with axios

Let's have a bit of fresh air and switch to axios for data fetching. It's a nice library similar to fetch but has less boilerplate, better error handling, and can monitor data loading (totally not needed for our case 😅).
I've written a Knowledge Pill for fetching data from an API using fetch via a custom hook. The above code snippet is almost identical with the exception that it uses axios.get (less boilerplate, no check for .ok) instead and is named useApi and not useFetch like in the pill. For purposes of our Pokemon application, we don't need to use any other methods than the .get method from axios.
To learn more about custom useApi hook I highly recommend going through the above pill and comparing both solutions (please, play a little bit in the codesandbox with pokeAPI too).
It looks clearer when all the logic is extracted in our useApi hook. As you can see on the highlighted code, useApi returns error, isLoading, and data. We need to extract results from data, rename it for declarativity purposes to pokemons and render as before.

What if there already exists a hook for data fetching? 🙈

Unfortunately (for me), I'm not a precursor of custom hooks for data fetching. We mentioned react-query in the introduction. Let's see how that can simplify our life. (I'll still leave useApi hook in the code sandbox for reference).
I skipped the setup of the QueryClientProvider from the react-query and focused on useQuery. You can read documentation to configure it in your project or take a look in the codesandbox (index.js).
useQuery hook has a very similar structure to our custom hook with small exceptions. The first parameter is the query name, in our case "pokemons" string argument. The second parameter is a function to execute the query, it could be .get method from axios but we used fetch in getPokemons function to showcase useQuery hook works with it.
It appears, we didn't really need to write any of the data fetching code and just use react-query. Although, I hope this data fetching journey opened your eyes, and either it's an abstraction or not, you know what you're doing when writing asynchronous code in React. 🙇‍♂️
As we spent quite some time on the data, let's make it pretty and shiny with the GridList component.

Using GridList and fetching Pokemon image

Going from the top, I added a couple of GridList related components for styling purposes. Then, I've implemented getPokemon function to receive the Pokemon data based on provided url. The function was used inside of a newly created PokemonTile component with a combination of react-query (please, notice anonymous function usage to pass an additional url argument).
After getting Pokemon data, I was able to render the PokemonTile to present it on the screen. Outer App component renders a list of PokemonTile components based on the pokemons query (limited to 100).

REST API, GraphQL, gRPC?

All our API calls were based on REST API so far but GraphQL is a great alternative. There is also a gRPC buzzword but I didn't work with it at all.
GraphQL is great as it has a single endpoint to rule them all, the client (you, browser) can decide how much data should be fetched, everything happens through queries and mutations. Additionally, it has an auto-generated schema feature (helps a lot to understand API structure, similar to e.g. Swagger, just built-in). On top of that, there is e.g. apollo-client library for React which supports cache management (you know, cache invalidation and naming things... 🙈) and has amazing hooks support out of the box.
Not going into the details. However, I've written another article to present simple usage of GraphQL query through pokeAPI with browser fetch. Interested? Check it out!

Summary

The Frontend journey never ends. To become a top-quality React Developer you need to get a good hang of data fetching. This was my first big series about explaining crucial topics based on project building, hopefully, you had some fun and finished the project with me along the way. 😊
... but if not, let's take a look at the preview of it one more time to avoid scrolling all the way top.
As I already mentioned in the related pill, time for you to turn this project into the best Pokedex online ever created! 🔥
Big thanks for reading the article, you're awesome! 🙇‍♂️
You can also find me on:
Thanks for all the support. ❤️
logo with a rocket of the BigDevSoon application

Level up your Frontend skills

Code real-world projects based on Figma designs.
spread the word
Did you like this post? Share it with the world! 🌐