How to Fetch Data with React Hooks
Tags: react, javascript
Published: 2019-12-14 09:03:35

_Read the original article [here](https://rahmanfadhil.com/fetch-data-with-react-hooks/)_

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](https://facebook.github.io/create-react-app) by running this command below.

```
$ npx create-react-app <YOUR_APP_NAME>
```

Or, I have already publish 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
```

## Fetch when component has loaded

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

```jsx
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](https://jsonplaceholder.typicode.com/), 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.

```jsx
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](https://reactjs.org/docs/hooks-state.html).

```jsx
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.

```jsx
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.

```jsx
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.

```jsx
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.

```js
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.

```jsx
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](https://github.com/zeit/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](https://reactjs.org/docs/concurrent-mode-suspense.html) integeration!