1

I'm learning react for past few days and while using useEffect hook i'm getting infite loop over setting my state variable.

Can anyone tell me what's going on and how to overcome this enter image description here

Here's my code

import React, { useState, useEffect } from "react";
import axios from "axios";

const TodoEntry = () => {

  const [todos, setTodos] = useState('');

  useEffect(() => {
    axios.get('http://localhost:5000/api/todos')
     .then(res => { setTodos(res.data); console.log(todos) })
     .catch(err => console.log(err))
  },[todos]);

  return (
    <div>
      <h1>Todo App</h1>
   </div>
  );
};

export default TodoEntry;

7
  • useEffect(() => { getTodos(); },[todos]); try this. Commented Jul 13, 2020 at 13:42
  • useEffect(() => getTodos(), []); since you only want to do this once, on mount. If you have a linter which throws an error, then you can wrap getTodos in a useCallback to memoize it (not create a new function reference every time we render) and add it back to the dependencies array, or put the getTodos code inside the useEffect hook. Commented Jul 13, 2020 at 13:46
  • @MichaelYaworski not a good idea to skip adding the dependencies in useEffect hook's dependency array Commented Jul 13, 2020 at 13:47
  • @Yousaf it's a good idea if you only want to do it on mount Commented Jul 13, 2020 at 13:49
  • @MichaelYaworski Is it safe to omit functions from the list of dependencies? Commented Jul 13, 2020 at 13:52

2 Answers 2

2

Couple of problems in your code:

  • Since getTodos function is a dependency of useEffect hook, every time state updates, new getTodos function is created which then triggers the useEffect hook.

  • You don't need to chain then function when using async-await syntax. You can just await the result of axios.get(...).

To fix the first problem of infinite loop, use one of the following options:

  • Wrap the getTodos function in useCallback hook. For details, see useCallback.

    Since, getTodos function calls displayTodos, you will need to wrap it in useCallback hook and add displayTodos in the dependency array of useCallback hook that wraps getTodos function. In my opinion, it is better to just remove the displayTodos function and update the state inside getTodos function

    const getTodos = useCallback(async () => {
       try {
          const res = await axios.get('http://localhost:5000/api/todos')
          setTodos(res.data);
       } catch(err) {
          console.log(err);
       }
    }, [setTodos]);
    

    Demo

    Edit cold-darkness-xgjwp

  • Put the code inside getTodos inside useEffect hook and remove the getTodos function.

    useEffect(() => {
      axios.get("http://localhost:5000/api/todos")
       .then(res => setTodos(res.data))
       .catch(err => console.log(err));
    
    }, [setTodos]);
    

    Demo

    Edit blissful-darkness-1q7ng

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you Yousaf, I've tried the second method and got the correct result.
Note that is it safe to omit setTodos from the dependency array since it is a function from the useState hook: reactjs.org/docs/hooks-reference.html#usestate "React guarantees that setState function identity is stable and won’t change on re-renders. This is why it’s safe to omit from the useEffect or useCallback dependency list."
@MichaelYaworski yes it is safe but still i don't mind adding it as a dependency because it keeps me in the habit of not missing the dependencies
0

This is because the dependency list for your useEffect call is a function. You probably meant to add the todos data itself.

  useEffect(() => {
    getTodos();
  },[todos]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.