TLDR: Is the following middleware for Redux okay or is it a bad idea / bad practice? If it's bad, how else would you use dispatch
with pipe or compose (in a declarative way)? For ES6 version see further down. I initially wanted to open on issue on the Redux GitHub, but it apparently only allows bug reports and refers you to StackOverflow ♂️
// Purpose: have dispatch return its payload so that it
// can be used in pipes or compositions
export default function createPayloadReturner() {
return function wrapDispatchToAddPayloadReturn(next) {
return function dispatchAndReturn(action) {
function wrappedDispatch() {
next(action);
return action.payload;
}
if (action.payload) {
return wrappedDispatch();
}
return next(action);
};
};
}
Motivation: I'm currently learning functional programming. I'm writing a React app with Redux for my state management and Ramda to help me with functional programming.
I have a function called login
that is created by an asyncPipe
. It takes the credentials, logs the user in, saves the token, and uses that token to make an authenticated GET request to the server. The guest request returns a list of one or more objects (houses).
// Pseudo-code-ish
import { prop } from 'ramda';
const asyncPipe = (...fns) => x => fns.reduce(async (y, f) => f(await y), x);
const login = asyncPipe(
loginRequest,
prop('token'),
setToken,
getHouses,
)
// later (currently without the middleware)
const houseList = await login(credentials);
Now comes the issue. First, I would like to dispatch
the list of restaurants (dispatch(addHouses(houseList))
). Next, if there are more than one houses I would like to navigate the user to a list screen so he can pick a house. If there is just one house I would like to immediately navigate him to that house and pick it. Picking means dispatch(pickHouse(house))
.
I asked about this problem in general in this question. A commenter suggested creating a middleware so that dispatch
returns the respective actions payload and can be used in a pipe.
Therefore, using the Redux docs, I wrote this:
export default () => next => action => {
const wrappedDispatch = () => {
next(action);
return action.payload;
};
if (action.payload) {
return wrappedDispatch();
}
return next(action);
};
Now you can use it in a asyncPipe
, pipe
or compose
function.
Is this the correct way to return a payload? (I've tested it and the middleware seems to work.) Is this middleware okay, or does it violate some best practices?