Skip to content
Advertisement

How to pass in multiple action creators to single listenerMiddleware in Redux Toolkit?

I want to save state into my database whenever any of its properties changes. I currently have two middlewares that would dispatch my saveTrip function.

The two middlewares are identical but listen to different actionCreators.

Store.js:

listenerMiddleWare.startListening({
    actionCreator: setOrigin,
    effect: async(action, listenerAPI) => {
        listenerAPI.cancelActiveListeners();
        // await listenerAPI.delay(1000)
        console.log("side effect origin");
        listenerAPI.dispatch(saveTrip(action.payload))

    }
})

listenerMiddleWare.startListening({
    actionCreator: setDestination,
    effect: async(action, listenerAPI) => {
        listenerAPI.cancelActiveListeners();
        // await listenerAPI.delay(1000)
        console.log("side effect destination");
        listenerAPI.dispatch(saveTrip(action.payload))

    }
})

Savetrip function:

export const saveTrip = createAsyncThunk(
    'trip/saveTrip',
    debounce(async (payload, thunkAPI) => {
        const trip = thunkAPI.getState().trip
        try {
            fetch(
                'http://localhost:5000/savetrip', {
                mode: 'cors',
                credentials: 'include',
                method: "post",
                body: JSON.stringify({trip}),
                headers: {
                    'Content-Type': 'application/json'
                },
            })
            .then(res => res.json())
            .then(response => {
                console.log(response)
                thunkAPI.dispatch(setMongoID(response))
            })
        } catch (error) {
            console.log(error);
        }
    }, 2000)
)

I am not even using the payload thats passed in when I call saveTrip as I’m saving the entries state. I don’t have any bugs, but my code seems redundant if I need more listeners. Is there a better approach to this? I basically want to save my state into DB whenever the state changes.

Advertisement

Answer

You can use matchers

listenerMiddleWare.startListening({
    matcher: isAnyOf(setOrigin, setDestination),
    effect: async(action, listenerAPI) => {
        listenerAPI.cancelActiveListeners();
        // await listenerAPI.delay(1000)
        console.log("side effect origin");
        listenerAPI.dispatch(saveTrip(action.payload))

    }
})

That said, you are using createAsyncThunk very wrong – your thunk will finish before the request is even made to the server, long before a response arrives. And you don’t need to dispatch something in the end, just return it. Thunks automatically dispatch a .fulfilled action.

Also, that debouncing will lead to very weird effects. You need to do that on another level, preferrably outside your dispatch.

export const saveTrip = createAsyncThunk(
    'trip/saveTrip',
     async (payload, thunkAPI) => {
        const trip = thunkAPI.getState().trip
        try {
            const result = await fetch(
                'http://localhost:5000/savetrip', {
                mode: 'cors',
                credentials: 'include',
                method: "post",
                body: JSON.stringify({trip}),
                headers: {
                    'Content-Type': 'application/json'
                },
            })
            const response = await result.json()
            return response
        } catch (error) {
            console.log(error);
        }
    }
)

// then use `saveTrip.fulfilled` in your matcher.
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement