DEV Community

loading...
Cover image for React useEffect fetching API

React useEffect fetching API

ShubhamTiwari909
Newbiew developer
・3 min read

Hello everyone today i will show you how to fetch API in react js using 'useEffect'.

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.

What does useEffect do?
By using this Hook, you tell React that your component needs to do something after render. React will remember the function you passed (we’ll refer to it as our “effect”), and call it later after performing the DOM updates. In this effect, we set the document title, but we could also perform data fetching or call some other imperative API.

Does useEffect run after every render? Yes! By default, it runs both after the first render and after every update.

Lets get dive into the code now-

First we will import the required modules

import React,{useState,useEffect} from 'react'
/*here we have imported the useState to change the state of the
 data when the data gets update on the end point and useEffect
 is used to fetch the data from the api 
and it will run on every render
*/
Enter fullscreen mode Exit fullscreen mode

Here we are fetching data from a fake api called jsonPlacenholder api which gives us data of a todo list with 'pending' and 'completed' status

 const [todos, setTodos] = useState([]);
//useState is set to an empty arraya and later 
//we will fetch the data from the end point 
//and will store in the 'todos' array
Enter fullscreen mode Exit fullscreen mode

useEffect -

 useEffect(() => {
    fetch('http://jsonplaceholder.typicode.com/todos')
    .then(res => res.json())
    .then((data) => {
      setTodos(data)
      console.log(todos)
    })
 }, [todos]);
Enter fullscreen mode Exit fullscreen mode
  1. fetch is used to fetch the api from end point
  2. Then we set the state of todo to the data we have fetched from the API.
  3. In the last line of it [todos] is the dependency on which useEffect depends on.

Then we map the data using map function

{todos.map((todo) => (
             <div className="card bg-dark text-light my-3">
               <div className="card-body">
                 <h5 className="card-title">{todo.title}</h5>
                    <h6 className="card-subtitle mb-2 text-muted">
                      { todo.completed &&
                      <span>
                        Completed
                      </span>
                      }
                      { !todo.completed &&
                      <span>
                        Pending
                       </span>
                      }              
                   </h6>
              </div>
           </div>
          ))}
Enter fullscreen mode Exit fullscreen mode

Full source code -

import React,{useState,useEffect} from 'react'
import Fade from 'react-reveal/Fade'
import {Navbar,NavbarBrand,NavbarToggler,Nav,NavItem,NavLink,Collapse} from 'reactstrap';
import './App.css'
function App() {

  const[toggle,setToggle] = useState(false);
  const isToggle = () => setToggle(!toggle);
  const [todos, setTodos] = useState([])

  useEffect(() => {
    fetch('http://jsonplaceholder.typicode.com/todos')
    .then(res => res.json())
    .then((data) => {
      setTodos(data)
      console.log(todos)
    })
    .catch(console.log)
    }, [todos])

  return (
    <div className="">    
    <h1 className="text-primary text-center display-4 mb-5">React fetch api using useEffect</h1>
      <div className="text-center" style={{display:"block",width:"50%",margin:"0 auto"}}>
        <div style={{display:"flex",flexDirection:"column",justifyContent:"center",justifyItems:"center",width:"100%"}}>
          {todos.map((todo) => (
             <div className="card bg-dark text-light my-3">
             <div className="card-body">
               <h5 className="card-title">{todo.title}</h5>
               <h6 className="card-subtitle mb-2 text-muted">
               { todo.completed &&
                 <span>
                 Completed
                 </span>
               }
               { !todo.completed &&
                 <span>
                   Pending
                 </span>
               }              
               </h6>
             </div>
           </div>
          ))}
        </div>
      </div>
    </div>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

Here is the Output-

Screenshot (5)
I am newbie developer.So , if you find any mistake regarding any post Please highlight it
THANK YOU FOR READING THIS POST.

NOTE- In the example , we have bootstrap classes so , use bootstrap cdn or install and import it using npm or yarn package manager

Discussion (17)

Collapse
miketalbot profile image
Mike Talbot • Edited

That fetch is going to happen 2x at the start. The first time when todos is [] and then it will happen again when it's the result of the fetch as the useEffect deps will have changed. Then actually doesn't it just keep going because the object is different in todos?

Collapse
shubhamtiwari909 profile image
ShubhamTiwari909 Author

I am still learning so don't know much about in detail for now

Collapse
rbluena profile image
Rabii Luena

I admire you on the fact that you are still learning but you still want to each others from what you have learned so far. That is a winning attitude right there. I wanted to help but LUKE already did.

Thanks for sharing.

Thread Thread
shubhamtiwari909 profile image
ShubhamTiwari909 Author

Thank you

Collapse
lukeshiru profile image
LUKESHIRU • Edited

You just have to remove the [todos] in useEffect (leaving only []) and then the fetch will only run in the first render of the component.

Collapse
lukeshiru profile image
LUKESHIRU

I recommend you take a look at React Query for this kind of stuff. They provide a bunch of useful functions and hooks to deal with API interactions and is way more robust than doing your own thing.
If you still want to do your own thing, I recommend to make some of your code more reusable, something like this:

/**
 * Curried fetch with JSON parsing.
 *
 * @template {Record<PropertyKey, unknown>} ResponseType
 * @param {RequestInit} init
 */
const fetchJSON =
    init =>
    /**
     * @param {RequestInfo} input
     * @returns {() => Promise<ResponseType>}
     */
    input =>
    () =>
        fetch(input, init).then(response => response.json());

// We use the curried function above to create a `getJSON` function
// from it, and we can set stuff like headers, auth, etc.
const getJSON = fetchJSON({ method: "GET" });

// We then create a getToDos function that will return
// a function that does the fetch with everything set...
const getToDos = getJSON("http://jsonplaceholder.typicode.com/todos");

// Finally, we use it:

const App = () => {
    const [todos, setTodos] = useState([]);

    useEffect(() => void getToDos().then(setTodos).catch(console.error), []);

    // ...
Enter fullscreen mode Exit fullscreen mode

Cheers!

Collapse
shubhamtiwari909 profile image
ShubhamTiwari909 Author

Thank you for this
I will try these things also

Collapse
j3ffjessie profile image
J3ffJessie

Great tutorial and setup. As others have pointed out you would want to leave out the dependency todos from your useEffect so that it doesn’t loop but overall you were thorough with your explanation and I believe you understand useEffect pretty well. Thank you for writing this article.

Collapse
shubhamtiwari909 profile image
ShubhamTiwari909 Author

I am still at the learning stage and I even don't have 6-8 months of experience for now. So,kind of newbie here

Collapse
j3ffjessie profile image
J3ffJessie

We all start there and you are grasping concepts very well. Keep up the hard work and you will do fine. Posting articles like this and getting feedback will help as well. You are doing great. Keep pushing forward.

Thread Thread
shubhamtiwari909 profile image
ShubhamTiwari909 Author

Thank you

Collapse
tmartinri profile image
tmartin-ri

I would say that if you only want it to run the first time your component loads you should leave the useEffects dependency empty but at my work we use exhaustive deps on the linter and it would throw an error for emptying the dependency array. Instead I would recommend putting the fetch in an if statement that checks todos.length === 0

Collapse
shubhamtiwari909 profile image
ShubhamTiwari909 Author

Yes it will also work good

Collapse
ryelbanfield profile image
Ryel Banfield

Appreciate the awesome tutorial dude! However your fetch would end up in an endless loop. To run the fetch just once you would want to leave your useEffect dependency empty. 😊👍

Collapse
shubhamtiwari909 profile image
ShubhamTiwari909 Author

But when I leave it empty it throws error of empty dependency

Collapse
dhwajsharma profile image
Dhwaj Sharma

Thanks mate

Collapse
shubhamtiwari909 profile image
ShubhamTiwari909 Author

welcome buddy