1

Following some tutorial, I made a todo app and is now working on connecting it to the database. But doing so, while making an axios.get request its been called indefinitely.

My code

import React from "react"
import Header from "./Header"   
import Footer from "./Footer"
import Note from "./Note"
import CreateArea from "./CreateArea"
import axios from "axios"

function App(){
    const [notes, setNotes] = React.useState([]);

    React.useEffect(()=>{
        axios.get('http://localhost:3001/user')
        .then(res=>{
            const entry = res.data;
            setNotes(()=>{
                return [...entry];
            })
        })
        .catch(err =>{
            console.log("Error: "+err);
        })
    })



    function addNote(newNote){
        axios.post('http://localhost:3001/user', newNote)
        .then(res=>{console.log(res.data)})
        .catch(err=>{console.log("Error: "+err)})
        setNotes((prevNotes)=>{
            return [...prevNotes, newNote];
        });
        console.log(newNote);
    }
    function deleteNote(id){
        setNotes(prevNotes =>{
            return prevNotes.filter((noteItem, index)=>{
                console.log(noteItem);
                return index !== id;
            });
        });
    }
    return (
        <div>
            <Header />
            <CreateArea onAdd={addNote} />

            {notes.map((noteItem, index)=>{
                return <Note key={index} id={index} title={noteItem.title} content={noteItem.content} onDelete={deleteNote} />
            })}

            <Footer />
        </div>
    )
}
export default App;

I looked around and landed on this thread Axios.get() ReactJS. Following this I added the useEffect but still infinite calls are being made.

Striker
  • 67
  • 7

2 Answers2

5

The effect is run infinitely since you're not passing an array of dependencies as the second argument to the useEffect call. Pass an empty array if you only want to run the effect when the component mounts.

From the docs:

If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run. This isn’t handled as a special case — it follows directly from how the dependencies array always works.

React.useEffect(() => {
  axios
    .get('http://localhost:3001/user')
    .then((res) => {
      setNotes(res.data)
    })
    .catch((err) => {
      console.log('Error: ' + err)
    })
}, []) // an empty array of dependencies

If you set up eslint-plugin-react-hooks, it would display a warning to add setNotes to the dependency array since the effect depends on it. It's totally fine to add it since the function's reference won't change on re-renders.

React.useEffect(() => {
  axios
    .get('http://localhost:3001/user')
    .then((res) => {
      setNotes(res.data)
    })
    .catch((err) => {
      console.log('Error: ' + err)
    })
}, [setNotes])

This is unrelated to the question but you shouldn't hardcode the API URL. Use environment variables. If you're using Create React App, you can add environment variables prefixed with REACT_APP_ to .env or you can use dotenv-webpack if you have a custom Webpack setup.

Arun Kumar Mohan
  • 11,517
  • 3
  • 23
  • 44
  • @prashantgarg The code in my answer has the required changes. Let me know if you have any questions. – Arun Kumar Mohan Apr 05 '21 at 06:45
  • Could you please elaborate on this by making changes to it? Earlier I tried doing this without useEffect where I made a variable ```entry``` and stored the content of ```res.data```. By doing so I was able to get the value in the form of an array inside the ```.then``` but as soon as I move out of ```.then``` my ```entry``` variable was reset to ```undefined``` – Striker Apr 05 '21 at 06:49
  • @prashantgarg Were you trying to access the variable outside the `then` block? That won't work since the call is asynchronous and the value is only available in the `then` block. – Arun Kumar Mohan Apr 05 '21 at 06:51
  • Here is what I was trying to do ``` var entry; axios.get('http://localhost:3001/user') .then(res=>{ entry = res.data; }) .catch(err =>{ console.log("Error: "+err); }) console.log(entry) ``` – Striker Apr 05 '21 at 06:54
  • @prashantgarg `axios.get` is asynchronous and `console.log(entry)` gets executed before the promise resolves. That's why `undefined` is logged. I would recommend reading [this](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) answer to gain a better understanding. – Arun Kumar Mohan Apr 05 '21 at 06:56
0

Doing so, the useEffect is called on every function call. You should patch the code by adding something which never change overtime.

React.useEffect(()=>{
    //
    },
    []  //this makes the effect to be called the very first time only
)
Mario Vernari
  • 6,649
  • 1
  • 32
  • 44