I created a react hook to perform api calls inspired by this article.
The hook looks as followed:
function useApi<T>(apiFunc: (...args: Array<any>) => Promise<AxiosResponse<T>>) {
const [data, setData] = useState<T | null>(null);
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const controllerRef = useRef(new AbortController());
const request = async (...args: Array<any>) => {
setLoading(true);
try {
const response = await apiFunc(...args);
setData(response.data);
} catch (error: any) {
setError(error.message || 'Unknown Error');
} finally {
setLoading(false);
}
};
return { request, cancel, data, error, loading };
};
Now I am using the hook in a component in the useEffect function:
const vacancyApi = useApi(getVacancy);
useEffect(() => {
if (!!id) {
vacancyApi.request(id);
}
}, [id, vacancyApi]);
The problem is that when I add vacancyApi
to the dependency array it results in an endless loop because vacancyApi is updated by the hook which then calls useEffect again.
I could just not add vacancyApi
to the dependency array and it works but that seems ugly to me and not the right thing to do.
I also can't move the function out of the component because it's a hook and has to be created inside the component.
In the articles comments I read that it could be a solution to wrap the request function into a useCallback hook. But I haven't figured out how to do it properly, I still had the same problem.
const request = useCallback(async (...args: Array<any>) => {
...
}, [apiFunc]);
Is there a solution where I can call the api only if the id changes without removing the dependency of vacancyApi
from the useEffect dependencies?