DEV Community

Mario
Mario

Posted on • Originally published at mariokandut.com on

How to fetch data with React Hooks

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.

💰: Start your cloud journey with $100 in free credits with DigitalOcean!

useEffect

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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

Top comments (2)

Collapse
 
psyduck profile image
psyduck • Edited

i always use empty array : useEffect(() => {}, []) it similars componentDidMount()

Collapse
 
mariokandut profile image
Mario • Edited

@psyduck , it really depends what your use case is. A cleanup should be always provided, you can also read more about it how-to-use-useeffect-hook-in-react/.