0

So I am working on a small personal project that is a todo app basically, but with a backend with express and mongo. I use useEffect() to make an axios get request to the /all-todos endpoint that returns all of my todos. Then inside of useEffect()'s dependency array I specify the todos array as dependency, meaning that I want the useEffect() to cause a rerender anytime the tasks array gets modified in any way. Take a look at this:

export default function () {
    const [todos, setTodos] = useState([]);
    const currentUser = JSON.parse(localStorage.getItem('user'))._id;

    useEffect(() => {
        function populateTodos () {
            axios.get(`http://localhost:8000/api/all-todos/${currentUser}`)
                .then(res => setTodos(res.data))
                .catch(err => console.log(err));
        }

        populateTodos();
    }, [todos]);

    console.log(todos);

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

So I placed that console.log() there to give me a proof that the component gets rerendered, and the problem is that the console.log() gets printed to the console forever, until the browser gets slower and slower. How can I make it so that the useEffect() gets triggered obly when todos gets changed?

code_dude
  • 951
  • 2
  • 15
  • 28
  • Remove todos from your useEffect dependency, add setTodos instead. – Nayan shah Mar 17 '20 at 17:49
  • It is doing an infinite loop because the state you are setting inside useEffect is the same one on the dependencies list as well. So whenever your state changes, the useEffect will run again. – Nayan shah Mar 17 '20 at 17:51

1 Answers1

1

You should execute the hook only if currentUser changes:

export default function () {
    const [todos, setTodos] = useState([]);
    const [error, setError] = useState(null);

    const currentUser = JSON.parse(localStorage.getItem('user'))._id;

    useEffect(() => {
        function populateTodos () {
            axios.get(`http://localhost:8000/api/all-todos/${currentUser}`)
                .then(res => setTodos(res.data))
                .catch(err => setError(err));
        }

        populateTodos();
    }, [currentUser]);

    console.log(todos);

    if (error) return (
        <div className="App">
            There was an error fetching resources: {JSON.stringify(error)}
        </div>
    )

    return (
        <div className="App">
            ...
        </div>
    );
}
Rashomon
  • 5,962
  • 4
  • 29
  • 67