How to fetch data with React Hooks
© https://reactjs.org/

How to fetch data with React Hooks

Fetch data with useState and useEffect Hooks in React

ByMario Kandut

honey pot logo

Europe’s developer-focused job platform

Let companies apply to you

Developer-focused, salary and tech stack upfront.

Just one profile, no job applications!

Short reminder what React Hooks are, and here useState and useEffect hooks in detail.

This blog article is about how to fetch data with React hooks or how to fetch data with useEffect.

useEffect

💰 The Pragmatic Programmer: journey to mastery. 💰 One of the best books in software development, sold over 200,000 times.

The Effect 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.

The useEffect Hook can be understood as componentDidMount, componentDidUpdate, and componentWillUnmount combined in the React class lifecycle methods.

Let's start with a "real" example. We want to fetch articles from hackernews.com with a specific topic and display the resulting articles in a list with links to the corresponding article. HackerNews has a search API, which is powered by Algolia and it can be queried. As a query string you can use whatever you want, I will use react. The HackerNews API is public, free, and well documented, Search Hacker News.

We start with scaffolding our app with Create React App and then open App.js.

Delete all the boiler plate besides the import and the return. Your App.js should look like this:

import React from 'react';

function App() {
  return <div></div>;
}

export default App;

We need a state to store the result from the api.

import React, { useState } from 'react';

function App() {
  const [data, setData] = useState({ articles: [] });

  return <div></div>;
}

export default App;

When we look at the API we see the data structure for the returned article. We need the ObjectID, the title and the url properties and can already make the list.

import React, { useState } from 'react';

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

  return (
    <ul>
      {data.map(item => (
        <li key={item.ObjectID}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  );
}

export default App;

Now we need to fetch the data from the API with the useEffect hook.

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

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

  useEffect(() => {
    // here goes the data fetching
  });

  return (
    <ul>
      {data.map(item => (
        <li key={item.id}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  );
}

export default App;

For fetching data we can use the fetch API or a third-party plugin like axios. I prefer the native fetch API.

The useEffect hook can't be async, so declare the async function inside the effect and then call it.

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

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

  useEffect(() => {
    const fetchData = async () => {
      const res = await fetch(
        'https://hn.algolia.com/api/v1/search?query=react',
      );
      const json = await res.json();
      setData(json.hits);
    };
    fetchData();
  });

  return (
    <ul>
      {data.map(item => (
        <li key={item.ObjectId}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  );
}

export default App;

Did you notice something? We are not passing the second argument to useEffect here. Don’t do this. This means useEffect runs on every render and could potentially cause an infinite loop. To fix this, we need to pass an array as the second argument. Have a look at the how to use the useEffect hook article.

The only variable that useEffect depends on is setData. Hence, we should pass the array [setData] here. Because setData is a setter returned by useState, it won’t be recreated every render, and so the effect will only run once.

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

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

  useEffect(() => {
    const fetchData = async () => {
      const res = await fetch(
        'https://hn.algolia.com/api/v1/search?query=react',
      );
      const json = await res.json();
      setData(json.hits);
    };
    fetchData();
  }, [setData]);

  return (
    <ul>
      {data.map(item => (
        <li key={item.ObjectId}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  );
}

export default App;

That's it. We fetched data with the useEffect hook. Next steps would be a loading indicator and error handling. This will be covered in an upcoming post.

TL;DR

  • useEffect makes fetching data easier
  • Always provide a cleanup function to useEffect, to avoid running on every render.
  • useEffect can't be async, use an async function inside useEffect

Thanks for reading and if you have any questions, use the comment function or send me a message @mariokandut.

If you want to know more about React, have a look at these React Tutorials.

References (and Big thanks):

ReactJS, Dave Ceddia, Robin Wieruch

Scroll to top ↑