Minimal Redux Setup

(disclaimer: This is not a post about best practices, but food for thought when dealing with Redux boilerplate)

The Redux docs have a great page . I’d like to take this to the extreme and explore the benefits of having the most minimal possible Redux setup.

To take a step back, consider what drove many of us “vanilla” React users to giving Redux a shot — the ability to connect arbitrary components to our global app state instead of passing down state and update functions through every node from App to leaves.

I found this to be very helpful, especially after adding React Router and discovering the need to clone children, passing in app state and various functions to update said state:

let children = Children.map(this.props.children, child => 
cloneElement(child, {
…this.props,
…this.state,
setState: payload => this.setState(payload)
})
})

Passing setState down to children may seem way too cavalier and for important applications I would agree, but not all apps are important or will have multiple maintainers or will have any users whatsoever. Sometimes you just want to make something that works, fast. Knowing what the minimum requirements are for a working program can be empowering.

Then I added Redux and suddenly had ten times as much code as I would have liked to have. I was trading brevity for predictability — actions for all the events in my app, action creators to wrap those and many reducers whose switch statements had a long list of cases. I didn’t think I was building a very complex application but it seemed like every little feature bloated my already verbose, though highly predictable, business logic.

Over time I noticed more logic being pushed up to thunks / epics / sagas, and reducers thinning out to be barely visible.

function reducer (state = init, action) {
switch (action.type) {
case 'UPDATE':
return {
...state,
...action.payload,
}
}
}

Some day later I needed to make another small app and thought to myself, “All I really want is a single store that notifies me on changes — maybe something I can add middleware to later if I want.” That’s all this app needs. What might that look like to setup?

import { createStore } from 'redux'
let init = { /* stuff */ }
function reducer (state = init, action) {
switch (action.type) {
case 'UPDATE':
return {
...state,
...action.payload,
}
}
return state
}
function update (payload) {
return {
type: 'UPDATE',
payload,
}
}
let store = createStore(reducer)
export { store, update }

That’s it. One reducer, one action and one action creator. I still get all the benefits of Redux the technology, without the overhead of boilerplate, which I could easily add later on if I wanted to.

Used in some random component:

import { connect } from 'react-redux'
import { update } from './store'
export default 
connect(state => state)(
({ dispatch, state }) =>
<div>
<h1>{state.title}</h1>
<button
onClick={e => dispatch(update({ title: 'so minimal!' }))}
>
Give'r
</button>
</div>
)

I can already hear someone telling me to use MobX.

I’ve used it. I like it. I like Redux better. ¯\_(ツ)_/¯

Keep minimal, my friends.

/* — — — — — — — — — — — */

BTW I highly recommend:

* recompose

* redux-actions