I found many similar questions here about React Hook useEffect has a missing dependency. I have already checked them, but I didn't find solutions as I faced. I want to pass redux thunk function as a parameter to React custom hook.
Below is my code and it is working fine. But, I got dependency missing warning, I don't want to add ignore warning eslint. If I add dispatchAction to dependency array list, it is dispatching again and again because redux thunk asyn function has fulfilled, reject, pending.
Custom Hook
const useFetchData = (dispatchAction, page) => {
const dispatch = useDispatch();
const [loadMoreLoading, setLoadMoreLoading] = useState(false);
const [errorMsg, setErrorMsg] = useState();
useEffect(() => {
const fetchData = async () => {
setLoadMoreLoading(true);
const resultAction = await dispatch(dispatchAction);
if (resultAction.meta.requestStatus === 'rejected') {
setErrorMsg(resultAction.payload.message);
}
setLoadMoreLoading(false);
};
fetchData();
}, [dispatch, page]);
return [loadMoreLoading, errorMsg]; // it is asking for adding dispatchAction.
My component
const SomeListing = ({userId}) => {
const [page, setPage] = useState(1);
const [loadMoreLoading, errorMsg] = useFetchData(
fetchPropertyByUserId({userId: userId, page: page}),
page,
);
}
So, is there any way to be able to add redux thunk function in react custom hook?
The function fetchPropertyByUserId
, when called i.e. fetchPropertyByUserId({userId: userId, page: page})
, returns an "actionCreator" function.
Hence, when you call this function at the place of first parameter of your hook useFetchData
, it returns a new "actionCreator" function each time (we know that hooks are called at each render):
In SomeListing.jsx:
const [loadMoreLoading, errorMsg] = useFetchData(
fetchPropertyByUserId({userId: userId, page: page}), // <-- Here: it returns a new "actionCreator" function at call (render)
page,
);
And, as soon as you put this function (first parameter of the hook i.e. dispatchAction
) as a dependency of useEffect
, it should cause an infinite execution of the effect because, now we know, that dispatchAction
is getting created (hence, changed) at every render.
In useFetchData.js:
export const useFetchData = (dispatchAction, page) => {
// ...
useEffect(() => {
const fetchData = async () => {
setLoadMoreLoading(true)
const resultAction = await dispatch(dispatchAction)
if (resultAction.meta.requestStatus === 'rejected') {
setErrorMsg(resultAction.payload.message)
}
setLoadMoreLoading(false)
}
fetchData()
}, [dispatch, dispatchAction, page]) // <-- "dispatchAction" added here
// ...
Pass a memoized actionCreator function:
In SomeListing.jsx:
export const SomeListing = ({ userId }) => {
const [page, setPage] = useState(1)
// Here: "fetchPropertyByUserIdMemo" is memoized now
const fetchPropertyByUserIdMemo = useMemo(
() => fetchPropertyByUserId({ userId: userId, page: page }),
[page, userId]
)
const [loadMoreLoading, errorMsg] = useFetchData(fetchPropertyByUserIdMemo, page)
// ...
}