Reputation: 4127
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
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
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