I have a problem that I can't seem to figure out why is happening.
I created a custom hook that makes an API call to the BE every time a "filter" or "page" is changed.
If the user changes some filter before the response is received, I successfully cancel the API call with the "old" filters and trigger the new correct api call with the updated filters.
I have a Redux store, and in it I have a "loading" property that keeps track if the API call si pending or finished. Just normal, plain no fancy redux store implementation with React.
Below is the custom hook that I created, that works as expected in terms of "canceling" the request when the filters/page change. I
export const useGetPaginatedDataWithSearch = (getFunction, page, searchValue, filters={}) => {
const dispatch = useDispatch();
useEffect(()=>{
const controller = new AbortController();
const abortSignal = controller.signal;
// to the initial filters,
// we want to add the page and search value
let params = {...filters};
params.page = page
params.search = searchValue;
dispatch(getFunction(params, abortSignal))
return () => {
controller.abort()
}
}, [dispatch, page, searchValue, getFunction, filters])
}
The "getFunction" parameter, is something like this.
export const getDrivers = (params= {}, abortSignal, endpoint) => {
return (dispatch) => {
dispatch(driversApiCallStart());
const url = endpoint ? endpoint : '/drivers';
return api.get(url, {params:params, signal: abortSignal})
.then((response) => {
let data = response.data;
dispatch(getDriversSuccess(data));
})
.catch((error) => {
const actionType = 'getDrivers';
throw parseError(dispatch, driversApiCallFail, error, actionType);
});
};
};
driversApiCallStart and parseError are some functions used across all the actions for the drivers store slice, and just update the "loading" or "error" state in redux store. Redux store uses the "immer" package, this is where the "draft" comes from in the below code.
case actionTypes.DRIVERS_API_CALL_START:
draft.loading = true;
break;
case actionTypes.DRIVERS_API_CALL_FAIL:
draft.loading = false;
draft.error = {
apiCall: action.payload.apiCall,
message: action.payload.message
};
break;
Now my problem is the following. This is the expected normal order of the "actions/trigers" whatever:
the cancel request is triggered when the filters change (OK)
cancel request goes in the .catch((error) block (OK)
.catch((error) block trigers "DRIVERS_API_CALL_FAIL" => draft.loading = false => spinner stops (OK)
new api call is made with the new filters "DRIVERS_API_CALL_START" => draft.loading = true; => spinner start (OK)
My problem is that the order in the app is:
1 => 2 => 4 => 3 (spinner is not displayed although the API call is "in progress").
Please check below print screen:
redux order in the app
Expected order behavior: 1 => 2 => 3 => 4 (spinner to be displayed white the API call is "in progress").