axel
axel

Reputation: 4127

How to solve `React Hook useEffect has a missing dependency` of `react-hooks/exhaustive-deps`?

I am here to ask something about react hooks and missing dependencies.

I try to be concise, this is warning message I have in my console

Compiled with warnings.

./src/views/categories/Categories.tsx
  Line 14:6:  React Hook useEffect has a missing dependency: 'dispatcher'. Either include it or remove the dependency array  react-hooks/exhaustive-deps

the code of the hook useEffect

const [categoriesList, dispatcher] = useCategoryList({})

useEffect(() => {
  !isOpenConfirmAddModal && dispatcher.fetchCategories()
}, [isOpenConfirmAddModal])

and this is the code of the custom hook useCategoryList

export const useCategoryList = (
  initialState: CategoriesData
): CategoriesListHook => {
  const [state, dispatch] = useReducer(categoryReducer, initialState)

  const fetchCategories = async () => {
    const categories = await getCategories()
    dispatch({ type: FETCH_CATEGORIES, data: categories })
  }

  // ....

  return [
    state,
    {
      fetchCategories
      // ...
    }
  ]
}

if I set the dispatcher as dependency

useEffect(() => {
  !isOpenConfirmAddModal && dispatcher.fetchCategories()
}, [isOpenConfirmAddModal, dispatcher])

and the effect in the application is an eternal loop of call to dispatcher.fetchCategories(), it seems that dispatch is constantly updating itself and the loop is never ending.

I tried some other coouple of attempts suggested in SO, but I never saw a dispatcher from a useReducer within a useEffect.

Ideas, thanks!

Upvotes: 2

Views: 345

Answers (2)

Mukul Kumar Jha
Mukul Kumar Jha

Reputation: 1082

You can make use of useCallback inside the custom hook itself to wrap the fetchCategories method giving its own dependency array.

const fetchCategories = useCallback(async () => {
  const categories = await getCategories()
  dispatch({ type: FETCH_CATEGORIES, data: categories })
},[<your dependencies>])
// check and update this dependency array

I think it is more abstract way to do this.

Upvotes: 0

HMR
HMR

Reputation: 39260

In your custom hook you can not re create fetchCategories and possibly other methods using useMemo:

export const useCategoryList = initialState => {
  const [state, dispatch] = useReducer(
    categoryReducer,
    initialState
  );

  const methods = React.useMemo(
    () => ({
      fetchCategories: async () => {
        const categories = await getCategories();
        dispatch({
          type: FETCH_CATEGORIES,
          data: categories,
        });
      },
      //other methods
    }),
    []//no dependencies
  );

  return [state, methods];
};

Now fetchCategies should not change during component life cycle so you can do:

const [categoriesList, {fetchCategories}] = useCategoryList({});
useEffect(() => {
  !isOpenConfirmAddModal && fetchCategories();
}, [fetchCategories]);

Upvotes: 1

Related Questions