Sentry Logo Debug Microservices & Distributed Systems

Join my free newsletter

Level up your dev skills and career with curated tips, practical advice, and in-depth tech insights – all delivered straight to your inbox.

4 min read
Older than 5 years

Trevor I. Lasn

Staff Software Engineer & Engineering Manager

How To Fetch Data From an API With React Hooks

Fetch data in React applications using the power of React Hooks

React Hooks let us write pure functional components without ever using the class syntax. Usually, but not always, the less code we have to write, the faster we can build our application.

Step 1. Refactoring From a Class to a Functional Component

Take this React class-based component. Our first step to using Hooks would be to refactor it into a functional component. Remember, you can use Hooks only with functional components.

import React, { Component } from "react";
export default class Planets extends Component {
state = {
hasErrors: false,
planets: {}
};
componentDidMount() {
fetch("https://swapi.co/api/planets/4/")
.then(res => res.json())
.then(res => this.setState({ planets: res }))
.catch(() => this.setState({ hasErrors: true }));
}
render() {
return <div>{JSON.stringify(this.state.planets)}</div>;
}
}

The component has hasError and planets state variables. When the component mounts, we call the Star Wars API and fetch the information.

Here’s how we would transform the component into a functional component.

import React, { useState } from "react";
const Planets = () => {
const [hasError, setErrors] = useState(false)
const [planets, setPlanets] = useState({})
componentDidMount() {
fetch("https://swapi.co/api/planets/4/")
.then(res => res.json())
.then(res => this.setState({ planets: res }))
.catch(() => this.setState({ hasErrors: true }));
}
return (
<div>{JSON.stringify(planets)}</div>
)
}
export default Planets;

Tada! A functional component with Hooks. There’s just one problem, though: Hooks don’t have lifecycle methods such as componentDidMount or componentWillMount.

Step 2. useEffect

The useEffect Hook lets you perform side effects in function components. Data fetching, setting up a subscription, and manually changing the DOM in React components are all examples of side effects.

import React, { useState, useEffect } from "react";
const Planets = () => {
const [hasError, setErrors] = useState(false);
const [planets, setPlanets] = useState({});
useEffect(() =>
fetch("https://swapi.co/api/planets/4/")
.then(res => res.json())
.then(res => this.setState({ planets: res }))
.catch(() => this.setState({ hasErrors: true }))
);
return <div>{JSON.stringify(planets)}</div>;
};
export default Planets;

useEffect is a React Hook that accepts a callback as its first argument. Inside the first argument, we perform all the effect-related tasks.

Import the useEffect from React, and replace componentWillMount with this Hook.

What does useEffect do?

By using this Hook, you tell React that your component needs to do something after rendering. React will remember the function you passed (we’ll refer to it as our “effect”) and call it later after performing the DOM updates.

But why is the state still our initial state {}? Because, there’s no this.setState({}) function inside functional components.

Step 3. Moving From this.setState({}) to Hooks

import React, { useState, useEffect } from "react";
const Planets = () => {
const [hasError, setErrors] = useState(false);
const [planets, setPlanets] = useState({});
useEffect(() => {
async function fetchData() {
const res = await fetch("https://swapi.co/api/planets/4/");
res
.json()
.then(res => setPlanets(res))
.catch(err => setErrors(err));
}
fetchData();
}, []);
return (
<div>
<span>{JSON.stringify(planets)}</span>
<hr />
<span>Has error: {JSON.stringify(hasError)}</span>
</div>
);
}
export default Planets;

Notice how we put a function inside the callback. The function is named fetchData and does exactly as it’s named.

If this looks more complicated, I assure you it’s not. Just like how we wrote a function inside componentDidMount, we do the same in the useEffect Hook.

To illustrate how simple it actually is, let’s move the fetchData function out of the Hook entirely.

import React, { useState, useEffect } from "react";
const Planets = () => {
const [hasError, setErrors] = useState(false);
const [planets, setPlanets] = useState({});
async function fetchData() {
const res = await fetch("https://swapi.co/api/planets/4/");
res
.json()
.then(res => setPlanets(res))
.catch(err => setErrors(err));
}
useEffect(() => {
fetchData();
}, []);
return (
<div>
<span>{JSON.stringify(planets)}</span>
<hr />
<span>Has error: {JSON.stringify(hasError)}</span>
</div>
);
};
export default Planets;

Note: If you want the useEffect to behave like the componentDidMount lifecycle event, pass an empty array as the second argument, like so:

useEffect(() => {
fetchData();
}, []);

Think of the second argument as the dependencies for that effect. If one of the dependencies has changed since the last time, the effect will run again.


Become a better engineer

Here are engineering resources I've personally vetted and use. They focus on skills you'll actually need to build and scale real projects - the kind of experience that gets you hired or promoted.

Many companies have a fixed annual stipend per engineer (e.g. $2,000) for use towards learning resources. If your company offers this stipend, you can forward them your invoices directly for reimbursement.


This article was originally published on https://www.trevorlasn.com/blog/how-to-fetch-data-from-an-api-with-react-hooks. It was written by a human and polished using grammar tools for clarity.

Interested in a partnership? Shoot me an email at hi [at] trevorlasn.com with all relevant information.