React | Fetch Data with useEffect Hook
Tags: react, javascript, webdev, programming
Published: 2022-09-17 14:01:56


Hello folks, today I will be talking about `useEffect` hook in React.

_Previosly I've written about about `useState` hook if you want to read that; [part 1](https://dev.to/ahmetmeliksah/usestate-one-of-the-most-common-hooks-that-you-will-be-using-in-react-npm) and [part 2](https://dev.to/ahmetmeliksah/usestate-one-of-the-most-common-hooks-that-you-will-be-using-in-react-objects-as-state-values-3hgg)_

So, what's `useEffect`? In short, we use this hook to tell React that our component needs to do something after each render. React will keep that (useEffect function) in mind, and trigger it after performing DOM updates. This can be used in many scenarios, but today I will use it for fetching data.

Fist, I will explain how it works, then I will use it for fetching data.

This is `index.js` component:

```javascript
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
```

`App.js` component:

```javascript
import { useEffect } from "react";

// css is from boiler plate (code that comes with React), I didn't code anything for styling
import "./App.css";

function App() {
  useEffect(() => {
    console.log(`useEffect comes AFTER page render`);
  });

  console.log(`Page is rendered`);

  return (
    <div className="App">
      <h1> useEffect </h1>
    </div>
  );
}

export default App;
```

If you go to console, you should see `Page is rendered` on top of `useEffect comes AFTER page render` because useEffect runs after each render. Now, this is out of the way, let's talk about **dependency list** in `useEffect` a bit. I will add a counter that only increments the value in `App.js` file.

Here's `App.js again`:

```javascript
import { useState, useEffect } from "react";

// css is from boiler plate (code that comes with React); however, I added a bit too :D
import "./App.css";

function App() {
  const [counter, setCounter] = useState(0);

  useEffect(() => {
    console.log(`useEffect come AFTER page render`);
  });

  const increment = () => {
    setCounter((prevVal) => prevVal + 1);
  };

  console.log(`page is RENDERED`);

  return (
    <div className="App">
      <h1> useEffect </h1>
      <h2> {counter} </h2>
      <button onClick={increment} className="btn">
        Increment
      </button>
    </div>
  );
}

export default App;
```

In short, the code above has a button that increments value of `counter`. _I don't want to be repetitive, so if you've got no clue about useState you can check [this](https://dev.to/ahmetmeliksah/usestate-one-of-the-most-common-hooks-that-you-will-be-using-in-react-npm). It helps understand how `increment` function works_

However, if you go to console on the browser, you will notice each time the value changes, `useEffect` hook gets triggered.

![showing hook](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ksx59pf1a93l2xste40m.png)

The reason for that is `useEffect` is called after **every** render _except_ if you add a second argument; **depency list**. If you want to fire `useEffect` only in initial render, then you've got to add an empty array as a second argument like so:

```javascript
useEffect(() => {
    console.log(`ONLY INITIAL RENDER`);
  }, []);
```
![only in initial render](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0mpg23v67utzzerdius7.png)

As you can see from the image above, it's rendered only once. OK... But what's the use of this thing that renders only once? This will prevent us from falling into an infinite loop when calling a function in `useEffect`, and for this example that function will be fetching data.

For now I will use a classic; https://jsonplaceholder.typicode.com.

Time to share the whole code and explain it in small chunks:

```javascript
import { useState, useEffect } from "react";

// css is from boiler plate (code that comes with React); however, I added a bit too :D
import "./App.css";

function App() {
  const [users, setUsers] = useState([]);

  const fetchUsers = async () => {
    const response = await fetch("https://jsonplaceholder.typicode.com/users");
    const users = await response.json();

    setUsers((prevUsers) => (prevUsers = users));
    console.log(users);
  };

  useEffect(() => {
    fetchUsers();
  });

  return <div className="App"></div>;
}

export default App;
```

First, we need to import `useEffect` and `useState` like so; `import { useState, useEffect } from "react";`.

```javascript
const fetchUsers = async () => {
    const response = await fetch("https://jsonplaceholder.typicode.com/users");
    const users = await response.json();

    setUsers((prevUsers) => (prevUsers = users));
    console.log(users);
  };
```

The function above should be asynchronous because we can never anticipate when the data will come, and without data we shouldn't be executing lines below (at least not without error handling), so I used `async`, `await` syntax. As you can see, I fetched data from _jsonplaceholder.typicode.com_ (obviously, used the exact "path" to get data) by using this line of code `const response = await fetch("https://jsonplaceholder.typicode.com/users");`. However, to work with that data, I got to convert it to a `json`, so I converted it to json like so; `await response.json()`. Finally, put that _json_ into a variable called `users`.

**Note:**
Do not confuse `users` variable that I use with `users` variable that I used in hook (`const users` VS. ` const [users, setUsers]`). Remeber, there's scope in JavaScript. So, `users` variable that's inside of `fetchUsers` function is not accessible outside of that function.

Finally, the code above sets `users` (in fetchUsers function) variable to `const [users, setUsers]` hook by this
code `setUsers((prevUsers) => (prevUsers = users));`.

**Note:**
`useState` hook automatically receives previous value as argument, and I like being explicit when I updat value of state. So, I explicitly write `prevVal = data` when I set new data to it. If it was a counter, I would've written `setCounter((prevCount)=> prevCount + 1)`. However,`setUsers(users)` would also work.

_We could use **axios** to make fetching easier, but this is a really simple example, so I didn't bother using it. Keeping **axios** for later_

The problem with the code above is that it will drag us down to an infinite loop. Why? Because `useEffect` runs after each render. Let me show the code again

```javascript
const fetchUsers = async () => {
    const response = await fetch("https://jsonplaceholder.typicode.com/users");
    const users = await response.json();

    setUsers((prevUsers) => (prevUsers = users));
    console.log(users);
  };

  useEffect(() => {
    fetchUsers();
  });
```

Code above will run `fetchUsers` function after initial render. Then, `fetchUsers` function will get data, and page will re-render. After that `useEffect` will run again. So, data will be fetched again, then `useEffect` will run again and so on. To avoid this, we add second argument which is an empty array, so this `useEffect` runs only on initial render.

```javascript
useEffect(() => {
    fetchUsers();
  }, []);
```

OK, so we fetched data, now let's use it. It will be an extremely simple usage though, I added this to the bottom of `App` component only:

```javascript
return (
    <div className="App">
      {users.map((user) => {
        return (
          <div key={user.id}>
            <h2> {user.name} </h2>
          </div>
        );
      })}
    </div>
  );
```

The code above, maps over `users` array and displays names of users in h2 tag. Logic behind the code above is similar to logic [here](https://dev.to/ahmetmeliksah/vuejs-basics-part-2-v-for-list-rendering-1fol). If that's not clear, please read [this](https://reactjs.org/docs/lists-and-keys.html#gatsby-focus-wrapper). Other than that, since list rendering is not topic of this blog post, I won't be covering that.

Final code looks like this:

```javascript
import { useState, useEffect } from "react";

// css is from boiler plate (code that comes with React); however, I added a bit too :D
import "./App.css";

function App() {
  const [users, setUsers] = useState([]);

  const fetchUsers = async () => {
    const response = await fetch("https://jsonplaceholder.typicode.com/users");
    const users = await response.json();

    setUsers((prevUsers) => (prevUsers = users));
    console.log(users);
  };

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

  return (
    <div className="App">
      {users.map((user) => {
        return (
          <div key={user.id}>
            <h2> {user.name} </h2>
          </div>
        );
      })}
    </div>
  );
}

export default App;
```

Alright that was it for today, we briefly talked about `useEffect` hook. The source that I used if [React documentation](https://reactjs.org/docs/hooks-effect.html) by the way.