Autodux

3 minute read

Autodux is a library, written by Eric Elliott, to help automate Redux boilerplate.

Autodux lets you create everything you need for a Redux app in a handful of lines of code:

const {
  reducer,
  actions,
  selectors
} = autodux({
  initial: {
    username: 'Anonymous',
    email: 'anonymous@example.com'
  }
})

In this single call to autodux, you get a Redux reducer and an action and selector for each key in the initial state object.

Reducer

An autodux reducer is just a standard Redux reducer that's automatically setup to handle autodux actions. It's used like any other Redux reducer:

const { reducer } = autodux({})

const store = createStore(reducer)

Actions

A call to autodux returns an actions object which contains a function for each key in the initial state. For example, using the initial state from the above example, we would get setters for username and email inside the actions object:

{
  setUsername: Function,
  setEmail: Function
}

When one of these is called, it behaves like any standard Redux action creator, e.g.

actions.setUsername('abcd'){
→   type: '/setUsername',
→   payload: 'abcd'}

Custom actions

As well as the autogenerated actions that autodux creates for you, you can define custom actions with whatever logic you like. For example, to update both username and email at once, we can define a custom action setBoth:

const {
  reducer,
  actions,
  selectors
} = autodux({
  initial: {
    username: 'Anonymous',
    email: 'anonymous@example.com'
  },
  actions: {
    setBoth: (state, payload) => ({
      ...state,
      username: payload.username,
      email: payload.email
    })
  }
})

These actions will be automatically integrated into the autodux reducer and are called like any other action creator:

actions.setBoth({
  username: 'Admin',
  email: 'admin@example.com'
}){
→   type: '/setBoth',
→   payload: {
→     username: 'Admin',
→     email: 'admin@example.com'}}

When passed to Redux's dispatch function, setBoth will update both the username and email properties of the Redux state:

store.getState(){
→   username: 'Anonymous',
→   email: 'anonymous@example.com'}

store.dispatch(
  actions.setBoth({
    username: 'Admin',
    email: 'admin@example.com'
  })
)

store.getState(){
→   username: 'Admin',
→   email: 'admin@example.com'}

Selectors

A call to autodux also returns a selectors object which, like actions, contains a function for each key in the initial state. These functions are selectors, which means they are functions for retrieving specific parts of the state tree. For example, using the initial state from the above example, we would get selectors for username and email:

selectors.getUsername(state)'abcd'

selectors.getEmail(state)'anonymous@example.com'

Custom selectors

Similarly to custom actions, custom selectors can be created too. For example, to select both username and email at once, we can define a custom getBoth selector:

const {
  reducer,
  actions,
  selectors
} = autodux({
  initial: {
    username: 'Anonymous',
    email: 'anonymous@example.com'
  },
  selectors: {
    getBoth: state => ({
      username: state.username,
      email: state.email
    })
  }
})

When called with the Redux state, getBoth will return an object with both the username and email properties from the Redux state:

const state = store.getState(){
→   username: 'Anonymous',
→   email: 'anonymous@example.com'}

selectors.getBoth(state){
→   username: 'Anonymous',
→   email: 'anonymous@example.com'}

Autodux in action

As an example of converting a Redux app to use autodux, I've created an example Redux app with a commit converting it to an autodux app. Most of the existing code stays the same, with the majority of changes being a simplification of the reducer and action creator boilerplate.