Search code examples
javascriptconfigurationreduxredux-thunk

Proper way to pass configuration into Redux action creators


What is considered the "Redux" way of injecting configuration into action creators?

Consider an async action creator:

export function login(username, password) {
    return (dispatch, getState) => {
        const service = Auth.createService(config); // <- that's the one

        service.login(username, password).then((data) => {
            const {token} = data;
            dispatch(success(token));
        }).catch((err) => {
            Logger.log(err);
        });
    };
}

As you can see - AuthService (and all other services) require some configuration, that normally defines things like: baseUrl, headers and more.

Having them required in the AuthService itself via something like:

import configfrom '../config/globalConfig`;

is sub-optimal for multitude of reasons and doesn't let you override them for a specific service instance.

Using a middleware (some extension over redux-thunk) would provide the ability to inject the configuration, but:

  1. it is most likely already injected via getState, since, to me, configuration is a part of the application state, especially if it is editable

  2. it still wouldn't allow overrides on per-creator basis

Passing the configuration, from container components, to the action creator directly this.props.dispatch(login(username, password, config));, to me, is extremely verbose.


Solution

  • I think this injectMiddleware from Este is fairly neat:

    // Like redux-thunk with dependency injection.
    const injectMiddleware = deps => ({ dispatch, getState }) => next => action =>
      next(typeof action === 'function'
        ? action({ ...deps, dispatch, getState })
        : action
      );
    

    This lets you write action creators like

    export function login(username, password) {
       return ({ dispatch, getState, authService }) => {
    

    and inject authService while initializing the middleware.