Reputation: 23
I'm implementing an epic for a backend call. The response doesn't get handled as expected.
For my implementation I'm using these modules:
Action.ts
export const callBackendAction = createStandardAction('data/GET')();
export const callBackendCompletedAction = createStandardAction('data/LOADED')<IResultDataDTO[]>();
Epic.ts
export const callBackendEpic: Epic<RootAction, RootAction> = action$ =>
action$.pipe(
filter(isActionOf(callBackendAction)),
switchMap(async () =>
from(axiosBackendCall())
.pipe(
switchMap(({ data }) => {
return of(callBackendCompletedAction(data.map(data)))
}),
catchError(error => of(console.log(error)))
)
),
catchError(error => of(console.log(error)))
);
Reducer.ts
export interface IcallBackendReducerState
{
data: {}[];
pending: boolean;
}
const initialState : ICallBackendReducerState =
{
data: [],
pending: false
}
export const callBackendReducer = createReducer(initialState)
.handleAction(callBackendAction, (state: ICallBackendReducerState): ICallBackendReducerState => (
{ ...state, pending: true }
))
.handleAction(callBackendCompletedAction, (state: ICallBackendReducerState, action: PayloadAction<string, any>) => ({
...state,
pending: false,
data: action.payload
}));
Redux throws an error which could be related to this problem:
Error: Actions must be plain objects. Use custom middleware for async actions.
My expected output would be a backend call which triggers the reducer to set the pending state to true. <--- this matches the actual output
By receiving the response the reducer should be triggered to update the state with the data and a pending state of false. <--- this doesn't happen
Having a look at the network traffic in my browser shows that the call does complete. The problem is that it's not handled properly.
Upvotes: 1
Views: 181
Reputation: 96889
It looks like the problem is on these two lines:
switchMap(async () =>
from(axiosBackendCall())
By using async
you make the inner function return a Promise but then you use from()
that returns an Observable so in fact this arrow function return Promise<Observable>
which is not what you want. switchMap
will only subscribe to the Promise and not the nested Observable so redux
is confused why instead of an action you're passing Observable
.
So the fix is simple, just don't use async
because you don't even need it there. from
will handle the promise returned from axiosBackendCall()
automatically (I'm assuming axiosBackendCall
returns a Promise).
switchMap(() =>
from(axiosBackendCall())
.pipe(...)
),
Upvotes: 2