7

My objective here is to call an action inside a useEffect.

const ShowTodos = (props) =>{
   useEffect(()=>{
    props.fetchTodos()
   },[])
} 
const mapStateToProps = (state)=>{
  return {
    todos:Object.values(state.todos),
    currentUserId:state.authenticate.userId
  }
}

export default connect(mapStateToProps,{fetchTodos})(ShowTodos)

It works fine but I got a warning

React Hook useEffect has a missing dependency: 'props'. Either include it or remove the dependency array  react-hooks/exhaustive-deps.

But if I'm going to add props as my second parameter in my useEffects then it will run endlessly.

My first workaround here is to use the useRef but it seems that it will always re-render thus re-setup again the useRef which I think is not good in terms of optimization.

const ref = useRef();
  ref.current = props;
  console.log(ref)


  useEffect(()=>{
  ref.current.fetchTodos()
  },[])

Is there any other workaround here ?

ajbee
  • 3,511
  • 3
  • 29
  • 56
  • Dan Abramov also has a deep explanation for this case at https://overreacted.io/a-complete-guide-to-useeffect/. Worth reading. – Hongbo Miao May 07 '19 at 22:00

2 Answers2

10

That is an eslint warning that you get if any of the dependency within useEffect is not part of the dependency array.

In your case you are using props.fetchTodos inside useEffect and the eslint warning prompts you to provide props as a dependency so that if props changes, the useEffect function takes the updated props from its closure.

However since fetchTodos is not gonna change in your app lifecycle and you want to run the effect only once you can disable the rule for your case.

const ShowTodos = (props) =>{
   const { fetchTodos } = props
   useEffect(()=>{
     fetchTodos()
     // eslint-disable-next-line import/no-extraneous-dependencies
   },[])
} 
const mapStateToProps = (state)=>{
  return {
    todos:Object.values(state.todos),
    currentUserId:state.authenticate.userId
  }
}

export default connect(mapStateToProps,{fetchTodos})(ShowTodos)

You however can solve the problem without disabling the rule like

const ShowTodos = (props) =>{
   const { fetchTodos } = props
   useEffect(()=>{
     fetchTodos()
   },[fetchTodos])
} 

I however will recommend that you know when exactly should you disable the rule or pass the values to the dependency array.

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • @jt25, Well yes you must know when exactly to do what. You can read more about how to take this decision in [this post](https://stackoverflow.com/questions/55786752/how-to-manipulate-context-attach-function-to-context-or-wrap-dispatch-in-hook/55865765#55865765) and [this](https://stackoverflow.com/questions/55840294/how-do-i-fix-missing-dependency-in-react-hook-useeffect/55854902#55854902) – Shubham Khatri Apr 30 '19 at 06:57
  • @skyboyer Thanks for the feedback. Yes that was a copy paste error – Shubham Khatri Apr 30 '19 at 10:46
3

You have to add fetchTodos to dependencies.

const ShowTodos = ({ fetchTodos }) => {
  useEffect(() => {
    fetchTodos();
  }, [fetchTodos])
  ...
}

or like this.

const ShowTodos = (props) => {
  const { fetchTodos } = props;

  useEffect(() => {
    fetchTodos();
  }, [fetchTodos])
  ...
}
Andrej Jurkin
  • 2,216
  • 10
  • 19