1

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Actions from '../actions';

export const UserComponent = ({ foo, baz, bar, user, fetchUser }) => {
  useEffect(() => {
    console.log('##### I WAS CALLED I WAS CALLED');
    fetchUser();
  }, []);

  return (
      <div>
        <p>{user.name}</p>
        <p>{foo} {baz} {bar}</p>
      </div>
  );
};

UserComponent.propTypes = {
  fetchUser: PropTypes.func.isRequired,
  user: PropTypes.shape({}),
};

const mapActionsToProps = {
  fetchUser: Actions.fetchUser,
};

const mapStateToProps = ({ data }) => ({
  user: data.user,
});

export default connect(mapStateToProps, mapActionsToProps)(UserComponent);

I get an error 'React Hook useEffect has a missing dependency`

But If I put fetchUser in the dependency array

      useEffect(() => {
        console.log('##### I WAS CALLED I WAS CALLED');
        fetchUser();
      }, [fetchUser]);

It causes an infinite loop.

Adeel Imran
  • 13,166
  • 8
  • 62
  • 77
  • Have you tried leaving out the dependency array entirely, with `useEffect(() => {fetchUser()});`? In other words, don't pass a second argument to `useEffect`. – Brett DeWoody Jul 17 '19 at 09:12
  • Sorry, I updated my question. I have multiple props being passed to the component & I don't want to run useEffect every time those props change. I just want to fetch the users for the first time & not every time all the API's change. – Adeel Imran Jul 17 '19 at 09:17
  • What about using `user` as the second argument to `useEffect`, as you only want to update when `user` is changed. As in `useEffect(() => {fetchUser()}, [user]);` – Brett DeWoody Jul 17 '19 at 10:18
  • Yes true, but since I am using `fetchUser` in `useEffect` eslint error shows that I should add `fetchUser` in the dependency array as well. – Adeel Imran Jul 17 '19 at 10:19
  • 1
    Well, there's always `// eslint-disable-next-line react-hooks/exhaustive-deps` – Brett DeWoody Jul 17 '19 at 10:21
  • Does `fetchUser()` update the `user` prop? – Brett DeWoody Jul 17 '19 at 10:41
  • Solved it, I was using redux the wrong way in hooks. https://react-redux.js.org/next/api/hooks – Adeel Imran Jul 17 '19 at 12:15
  • 1
    It would be helpful to others who find this to post your solution as an answer and mark it as the solution. – Brett DeWoody Jul 17 '19 at 12:35

4 Answers4

7

The problem is that the function fetchUser changes in each render. You can solve the problem using "useCallback".

Example:

const initFetchMethod = useCallback(() => {
   return dispatch(fetchUserAction())
}, [dispatch])


useEffect(() => {
   initFetchMethod();
}, [initFetchMethod]);

References:

93sauu
  • 3,770
  • 3
  • 27
  • 43
1

I was using redux the wrong way in hook based components. This guide helped me a lot to use redux in functional components using hooks. https://react-redux.js.org/next/api/hooks

Adeel Imran
  • 13,166
  • 8
  • 62
  • 77
-1

The error says, you need to put all resources(vars/functions) used by the effect callback inside the dependencies array.

So, you need to put fetchUsers in the dependencies array. But, it will cause infinite loop. Because, fetchUsers instance is recreated everytime.

You need to maintain a loading state for the api response. And, put a check in the callback like below:

useEffect(() => {
    if(!user && !loading ) {
        fetchUser();
    }
}, [fetchUser, user]);
Karan
  • 285
  • 3
  • 9
-2

Disable the es-lint warning if fetchUser action does not change in app lifecycle

Since fetchUser is an redux action and it is not going to change in your app lifecycle, i would say you can safely disable the rule for your case.

useEffect(() => {
    console.log('##### I WAS CALLED I WAS CALLED');
    fetchUser();
    //eslint-disable-next-line import/no-extraneous-dependencies
  }, []);
Jørgen
  • 352
  • 2
  • 12