How to Fetch Data with React Hooks

December 14, 2019

In this tutorial, we're going to learn about new React feature called "Hooks". Well, I have written a lot of tutorials about React Hooks itself, but in this practicular post, we're going to learn how we can send an HTTP request asynchronously with this awesome React feature.

Getting Started

First, you obviously need a React application!

If you don't have it already, you can easily use create-react-app by running this command below.

$ npx create-react-app <YOUR_APP_NAME>

Or, I have already published the source code of this entire project. Go ahead and clone this repo from my GitHub.

$ git clone https://github.com/rahmanfadhil/react-hook-fetch.git

Fetch when component has loaded

Inside the component where you want to fetch a data, you need to add a useEffect hook.

import React, { useEffect } from "react"

export default function Example() {
  useEffect(() => {
    // Fetch data right here!
  }, [])

  return (
    <div>
      <h1>Cool app</h1>
    </div>
  )
}

Notice that I put an empty array at the second parameter. By default, useEffect gets called whenever a state in our component has changed. In this practicular scenario, we want to run this code once. So, the empty array tells our useEffect to run this code only when our component has rendered to the screen.

Then, we want to fetch our data by using the fetch API. You can use any HTTP client you want, but here, I just want to make things simple.

For this example, we're going to use JSONPlaceholder, an fake REST API that allows us to test our front-end applications. It's open-source, easy to use, and comes with a lot of resources already.

import React, { useEffect } from "react"

export default function Example() {
  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then(response => response.json())
      .then(data => console.log(data))
  }, [])

  return (
    <div>
      <h1>Cool app</h1>
    </div>
  )
}

Now we're trying to fetch the posts data from our fake API, transform the JSON respose into a JavaScript object, and for now, we just print out the final result into our console.

Open up your console tab, and you can see a bunch of fake posts that we just fetched from the API.

That's a good start!

Fetch result state

After we have successfully fetched our data, we need to store it somewhere in our component so that we can show the result to the screen. And the component state is the best place for it.

To setup a state for our component with Hooks, we can use the useState hook from React. You can read more about it here.

import React, { useEffect, setState } from "react"

export default function Example() {
  const [posts, setPosts] = useState([]) // new

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then(response => response.json())
      .then(data => console.log(data))
  }, [])

  return (
    <div>
      <h1>Cool app</h1>
    </div>
  )
}

Because our posts that we fetch is an array, we can define the default value of our state to be an empty array.

Cool! now we can store the posts that we just fetch by using the setPosts function.

import React, { useEffect, useState } from "react"

export default function Example() {
  const [posts, setPosts] = useState([])

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then(response => response.json())
      .then(data => {
        setPosts(data) // new
      })
  }, [])

  return (
    <div>
      <h1>Cool app</h1>
    </div>
  )
}

Then, the last thing we want to do is to display our data to the screen. We can loop through our posts array and display each item with HTML list.

import React, { useEffect, useState } from "react"

export default function Example() {
  // ...

  return (
    <div>
      <h1>Cool app</h1>
      {posts.map(item => (
        <li>
          <h2>{item.title}</h2>
          <p>{item.description}</p>
        </li>
      ))}
    </div>
  )
}

We also can add a placeholder into our list so that the user will see a loading bar or something instead of just a blank screen.

import React, { useEffect, useState } from "react"

export default function Example() {
  // ...

  return (
    <div>
      <h1>Cool app</h1>
      {posts.length > 0 ? (
        posts.map(item => (
          <li>
            <h2>{item.title}</h2>
            <p>{item.description}</p>
          </li>
        ))
      ) : (
        <h1>Loading posts...</h1>
      )}
    </div>
  )
}

Custom hook

We have successfully fetch a data and display it into the browser.

But here, I just want to show you how we can improve our code that we just write. So far, we put all of our code into a single component, this approach is not reusable, because if we want to do the same thing in a different component somewhere in our application, we need to rewrite this code over and over again. Or a bit better, copy-paste... 🤣

So, to prevent that, we can create a custom hook that we can use across components where we want to fetch the same data.

function usePosts() {
  const [posts, setPosts] = useState([])

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then(response => response.json())
      .then(data => {
        setPosts(data)
      })
  }, [])

  return posts
}

A custom hook is just a plain JavaScript function that contains hooks provided by React. So, the only thing we need to do is to extract our Example component logic into a reusable function

Finally, we can use this usePosts hook inside our Example component to get the current posts data.

import React, { useEffect, useState } from "react"

// ...

export default function Example() {
  const posts = usePosts() // new

  return (
    <div>
      <h1>Cool app</h1>
      {posts.length > 0 ? (
        posts.map(item => (
          <li>
            <h2>{item.title}</h2>
            <p>{item.description}</p>
          </li>
        ))
      ) : (
        <h1>Loading posts...</h1>
      )}
    </div>
  )
}

Now, your application works the same as before, but the code is much more cleaner and readable.

Quick note

If you want to have more advanced feature for data fetching with React Hooks, consider using SWR. An awesome React Hooks library for data fetching by zeit. It offers some additional features like loading state, error catching, custom fetcher, even React Suspense integration!

React & Redux Course

By the way, I have a FREE video course for you about React & Redux. Check it out and subscribe to my channel for more programming tutorials!

NODE.JS

How to Upload Files with Multer

Uploading files is an essential feature for web applications these days. This tutorial will cover how to upload files into a server from the…

JAVASCRIPT

How to Generate Unique ID in JavaScript

There are several ways to generate unique identifier in JavaScript. This could very useful in many cases, such as rendering list efficiently…

JAVASCRIPT

Full-Text Searching with Lunr.js

Lunr.js is a full-text search library for JavaScript. It allows us to perform a complex search to a collection of data. Its small, powerful…