I use redux with saga in my project, to make Axios requests in the store.
In order to give the user feedback about if the request has succeeded or not, I store an object in my store that holds two properties - errMsg
and isFetching
.
Whenever I make a request I set isFetching
to true, and then if I the request is successful, I trigger a success action which changes isFetching
to false.
I listen to isFetching
changes in my component, if the last state of isFetching
was false and now it changed to true, and there's no error message, then I trigger a success modal.
This implementation worked for me with a POST request, but when I tried it with a DELETE request, isFetching
never changed to true.
I tried debugging redux, and saw that the two actions were happening and that the store was changing, but the effect in my component wasn't triggered.
I added a delay between the changing of isFetching
to true, and then it worked.
Redux changes are too fast that useSelector isn't able to get the changes? is there a solution for this?
(I'm sorry for explaining the code, my project is in a closed network and I can't copy code here, if the explanation isn't good enough, please tell me and I'll try to manually write the code)
EDIT:
Adding code example:
The listener for changes in isFetching
:
const { isFetchingDelete, errMsgDelete } = useSelector(
(state: StoreState) => ({
isFetchingDelete: state.students.deleteState.isFetching,
errMsgDelete: state.students.deleteState.errMsg,
})
);
const prevIsFetchingDeleteRef = useRef<boolean>();
.........
useEffect(() => {
// trying to log the value of isFetchingDelete here, always logs false
if (!isFetchingDelete && prevIsFetchingDeleteRef.current) {
if (errMsgDelete) {
Swal.fire();
} else {
Swal.fire();
}
}
prevIsFetchingDeleteRef.current = isFetchingDelete;
}, [errMsgDelete, isFetchingDelete]);
The saga:
function* deleteStudentHandler(action: ActionType<typeof deleteStudent>) {
try {
yield call(StudentsService.delete, action.payload);
// if I add a delay of 1000ms here it's working
yield put(deleteStudentSuccess(action.payload));
} catch (e) {
yield put(deleteStudentFailure(e.message));
}
}
my reducer:
case: StudentsActionTypes.DELETE_STUDENT: {
return {
...state,
deleteState: {
...state.deleteState,
isFetching: true
}
}
}
case: StudentsActionTypes.DELETE_STUDENT_SUCCESS: {
return {
...state,
students: [
...state.students.filter((student) => student.id !== action.payload),
],
deleteState: {
...state.deleteState,
isFetching: false,
}
}
}
The code above works just fine on a post request that takes 300ms, but on a delete request that takes 2ms (json-server) it doesn't work. Adding where I stated in a comment in the code, makes the code work.
I finally understood why this was happening.
here, my problem was that StudentService.delete wasn't returning the Axios response, thus not returning a promise, and saga didn't have nothing to wait for..
function* deleteStudentHandler(action: ActionType<typeof deleteStudent>) {
try {
yield call(StudentsService.delete, action.payload);
// if I add a delay of 1000ms here it's working
yield put(deleteStudentSuccess(action.payload));
} catch (e) {
yield put(deleteStudentFailure(e.message));
}
}
hopefully this helps other people that may encounter this problem.