Skip to content

Instantly share code, notes, and snippets.

@bradharms
Last active December 9, 2015 19:15
Show Gist options
  • Save bradharms/03827796ebf6799130ef to your computer and use it in GitHub Desktop.
Save bradharms/03827796ebf6799130ef to your computer and use it in GitHub Desktop.
Allows Redux action creators to use a limited form of dependency injection.
/**
* Allows Redux action creators to use a limited form of dependency injection.
*
* To apply:
*
* import { applyMiddleware, createStore } from 'redux';
* import inject from './redux-inject';
*
* import dep1 from '.../dep1';
* import dep2 from '.../dep2';
*
* const createStoreWithMiddleware = applyMiddleware(
* // Note that inject() is a 'curried' function
* inject({dep1, dep2});
* )(createStore);
*
* After being applied, all action creators will be able to return a
* "dependency wrapper" function which will be given server-side versions of
* dependencies by name. The wrapper's return value will be passed to the
* next middleware via `next()`. Therefore, the signature of an action creator
* for such a function would look like this:
*
* const createFooAction = (payload) => ({dep1, dep2, ...deps}) => {
* // ...use dep1...
* // ...use dep2...
* return { type: FOO, ...payload };
* }
*
* Rational:
*
* This middleware was created to resolve a problem I faced while trying to
* write isomorphic model access code. My action creators needed to be used on
* both the client and the server, but they needed to access model data in
* different ways depending on which end they were currently running on. I
* decided the best way to do this was to provide the model access code via
* dependency injection, and the only way I could think to do it was using a
* redux middleware.
*
* Notes:
*
* This was intended to be used in conjunction with redux-thunk. When the two
* are used together, you must be careful to ensure that the action creators
* nest their functions in the correct order. This order will be the
* same order in which the middlewares are applied, as in this example:
*
* // --- configureStore.js ---
* const createStoreWithMiddleware = applyMiddleware(
* inject({dep1, dep2}),
* thunk
* )(createStore);
*
* // --- actions.js ---
*
* // RIGHT:
* const createFooAction = (payload) => (deps) => (dispatch) => {
* return dispatch
* }
*
* // WRONG: dispatch will receive the deps, and the deps will receive the
* // dispatch function.
* const createFooAction = (payload) => (dispatch) => (deps) => { ... }
*
* TODO: Don't depend on any third-party libraries (ie. lodash)
* TODO: Don't use ES6 syntax in definition
* TODO: Export as a stand-alone middleware from Github
*/
import _ from 'lodash';
export default deps => () => next => action =>
next(_.isFunction(action) ? action(deps) : action);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment