Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call a Redux Action inside a useEffect

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 ?

like image 588
ajbee Avatar asked Apr 30 '19 06:04

ajbee


People also ask

Can I dispatch action in useEffect?

Note: React guarantees that dispatch 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. You would need to pass either bound action creators or a reference to dispatch to your hook.

Can hook be called inside useEffect?

🔴 Do not call Hooks in class components. 🔴 Do not call in event handlers. 🔴 Do not call Hooks inside functions passed to useMemo , useReducer , or useEffect .

Can you use Redux with hooks?

React Redux includes its own custom hook APIs, which allow your React components to subscribe to the Redux store and dispatch actions.


2 Answers

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.

like image 129
Shubham Khatri Avatar answered Oct 19 '22 17:10

Shubham Khatri


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])
  ...
}
like image 3
Andrej Jurkin Avatar answered Oct 19 '22 18:10

Andrej Jurkin