I have a Redux createListenerMiddleware
defined in store.ts
:
export const listenerMiddleware = createListenerMiddleware()
listenerMiddleware.startListening({
actionCreator: myAction,
effect: (action, listenerApi) => {
// do job
}
})
Then myAction
action is defined in seprate MyAction-slice.ts
as follows:
const applicationSlice = createSlice({
name: 'app',
initialState: initialState,
reducers: {
myAction(state) {
// do pure functional code here
},
}
})
And it works fine when I call myAction
from a React component (first myAction
did its job, then createListenerMiddleware
for that particular action has been fired, e.g:
return (
<>
<button onClick={() => dispatch(myAction())}>
</>
)
However I also have a createAsyncThunk
defined in MyAction-slice.ts
as follows:
export const myAsyncAction = createAsyncThunk(
'app/async',
async () => {
const promiseData = await axios.get(`https://localhost:8888/hello`)
// handle errors for promiseData
return promiseData
}
)
And then I declare that thunk
inside createSlice
as follows:
...
extraReducers: (builder) => {
builder
.addCase(myAsyncAction.fulfilled, (state, payload) => {
// change state with a pure functional way
})
...
And also at the end of my MyAction-slice.ts
file I export actions as:
export const {myAction} = applicationSlice.actions
My problem is that I wish to somehow "hook" to myAsyncAction.fulfilled
reducer using createListenerMiddleware
, the same way I did for myAction
reducer. Is it even possible?
Your myAsyncAction.fulfilled
is also an ActionCreator
.
Add that to your MyAction-slice.ts
after createAsyncThunk
:
export const myAsyncActionCreator = myAsyncAction.fulfilled as AsyncThunkFulfilledActionCreator<AxiosResponse<any, any>, AsyncThunkConfig>
Also replace myAsyncAction.fulfilled
to myAsyncActionCreator
in your extraReducers
.
Then your createListenerMiddleware
would look like (store.ts
):
export const listenerMiddleware = createListenerMiddleware()
listenerMiddleware.startListening({
actionCreator: myAsyncActionCreator,
effect: (action, listenerApi) => {
// do job
}
})
Also don't forget to prepend
this listener to your configureStore
right after your reducers list:
export const store = configureStore({
reducer: {...}
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().prepend(listenerMiddleware.middleware),
})
Following same idea, you could also create myAsyncAction.rejected
action creator and export it in a same manner and use as:
listenerMiddleware.startListening({
actionCreator: myAsyncActionCreatorRejected