Using Aurelia and Redux together for good times all around

March 17, 2016   

Since playing with React and Redux I've really missed the separation of data flow and view logic this affords when working with Aurelia - in my opinion a fantastic framework to work with, but lacks data management features out-of-the-box. But alas, Redux to the rescue!

I'm going to show you how to use Redux with Aurelia in a pretty simple example with config for Redux Chrome DevTools, redux-logger and redux-thunk. Basically we're going to create a store and DI it everywhere, just like how in a React app you'd inject it through the router or create some kind of global. This assumes basic familiarity with Redux and Aurelia and the code can be found here.

First, let's install all the bits we need:

npm install --save redux redux-logger redux-thunk

FWIW I am using:
aurelia-* beta 1
redux 3.3.1
redux-logger 2.6.1
redux-thunk 2.0.1

Nice, now let's make a new file called store.js and put all our Redux code there. Normally I like to make a folder for all of this and break it up, but for the purpose of this example we'll keep it together.

import { createStore, applyMiddleware, compose } from 'redux'
import thunkMiddleware from 'redux-thunk'
import createLogger from 'redux-logger'

const loggerMiddleware = createLogger();

const sessionReducer = (state = {
  error: null,
  loggedIn: false
}, action) => {
  switch (action.type) {
    case 'LOGIN_SUCCESS':
      return {
        ...state,
        loggedIn: true,
        error: null
      };
    case 'LOGIN_FAILURE':
      return {
        ...state,
        loggedIn: false,
        error: action.error
      };
    default:
      return state;
  }
};

function configureStore() {
  return createStore(
    sessionReducer, // or combine some reducers
    compose(
      applyMiddleware(
        thunkMiddleware,
        loggerMiddleware
      ),
      window.devToolsExtension ? window.devToolsExtension() : undefined
    )
  )
}

export const reduxStore = configureStore();

Now let’s go over to our app.js (or whatever your root ViewModel is) and DI it in:

import {inject} from 'aurelia-framework';
import {reduxStore} from 'store';

@inject(reduxStore)
export class App {
  constructor(store) {
    this.store = store;
    this.store.dispatch({type: 'LOGIN_FAILURE', error: 'Oops! Wrong password matey.'});
  }
}

Because we're Dependency Injecting the store with @inject, we can do this in many different ViewModels and know we're getting the same instance everywhere, meaning we can just store.subscribe() and store.dispatcher.dispatch() in many places and know everything is talking to the same store.

Let me know if you found this easy to follow or have any questions, I've only recently started writing these kinds of quick tip blog posts!