1

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?

J. Hesters
  • 13,117
  • 31
  • 133
  • 249

0 Answers0