From Redux to Barracks

Matt McFarland
5 min readMar 17, 2017

After the debut of the Flux pattern, we saw a lot of libraries arrive on the scene with the goal of helping developers implement the flux architecture effectively.

Redux ended up being the most popular implementation of the flux architecture. Redux gained a lot of popularity because of things like hot module reloading and timeline debugging, and because of its rich ecosystem, I still believe that Redux is the best choice.

Barracks is better

Barracks is a less opinionated, unidirectional application state management library weighing a little over 1k. Because it is less opinionated, it could be implemented with React in a lot of different ways. In fact, Barracks itself does not imply the flux architecture. However, it works as a flux implementation incredibly well.

See the demo: http://barrax.surge.sh/

I set out to create a “todomvc” app using React and Barracks with the flux architecture in mind. It actually looks very similar to redux and is used almost the same way, so refactoring an application from redux to barracks can be done very easily.

What do Barracks and Redux have in common?

•Both derive from the Elm architecture
•Both use reducers to update state
•Both receive an event (action/message) that can be sent to reducers
•Reducers advance the state, but the state tree is immutable
•Both use middleware that can intercept incoming actions

What are the key differences?

•Redux has a rich ecosystem
•Barracks is closer to Elm
•Barracks has built-in functionality for async that closely follows the functional paradigm, using “effects” and “subscriptions”

If you have used redux and you enjoy the functional paradigm then you should consider Barracks.

Here’s how redux and barracks compare when dispatching an action:

dispatch({ type: UPDATE_TODO, text, id }) // redux 

You can actually just use the same API for dispatching an action if you curry! I personally went away from type though, and because barracks allows it, I do it this way:

dispatch(UPDATE_TODO, { text, id }) // barracks

The major difference though, is how barracks and redux compare with reducers.

Let’s look at a redux reducer:

function todoApp(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
return Object.assign({}, state, {
todos: [...state.todos,
{
text: action.text,
completed: false
}
]
})
default:
return state
}
}

Here’s how it looks with barracks:

const todoAppReducers = {
ADD_TODO: ({todos}, action) => ({
todos: [...todos,
{ id: action.id,
text: action.text
}
]
})
}

Barracks will copy state and merge new with old, so we don’t have to break reducers up, or use higher-order reducers.

The critical flaw in Redux is Async

The biggest flaw as I see it is how redux and async are being used today. If you look at functional languages such as Elm you can clearly see that Elm handles async in a much more concise way. You may disagree, but I think that using middleware for async is an anti-pattern. In addition, I’ve seen applications made with redux overloading their action creators with logic to handle async calls.

In a perfect world, I prefer the logic that modifies your state to be in a reducer. However, I’ve seen a lot of code being placed in actions, simply because people are trying to handle async calls, then finally call back to fire another action that goes through the reducer. This usually requires a middleware for redux, and while that isn’t necessarily a bad idea, it can grow to be quite a mess of code.

But the async problem in functional programming has already been solved, and unfortunately I’m seeing a lot of alternative “solves” enter the redux ecosystem and while some are innovative, nothing is as clean and simple as using Effects and Subscriptions, which come from Elm, and are available in Barracks.

Effects

Instead of relying on actions to dispatch more actions and so on for your async, or relying on middleware, you dispatch an action that is handled as an Effect. Actions can then remain to stay as simple POJOs, and Effects can contain all of your async code.

The Effect can then dispatch another action, or do nothing. But the effect handles it! What’s great is you have a singular place where your async code goes. It’s not in an action, its not spread across actions either, its in a single place and it’s key matches the action type.

effects: {
fetch: (state, data, dispatch, done) => {
http('foobar.com', function (err, res, body) {
if (err || res.statusCode !== 200) {
return done(new Error({
message: 'error accessing server',
error: err
}))
} else {
dispatch('moreFoo', { count: foo.count }, done)
}
})
}
}

Interoperability
Interoperating with 3rd party services

With Barracks, you can create “subscriptions” — which can be used to listen for specific events that may not be triggered by your code. These subscriptions can then dispatch an action.

The action then can be picked up by an effect, or by a reducer. This is a pattern used for interoperating with other libraries. Imagine that your emitWoofs(see below) was coming from a socket, or from a vue app or angular app, or even webrtc

subscriptions = {
emitWoofs: (send, done) => {
// emit a woof every second
setInterval(() => send('printWoofs', { woof: 'meow?' }, done), 1000)
}
}
effects = {
printWoofs: (state, data) => console.log(data.woof)
}

But barracks is not flux, so I did some things to implement it in a fluxxy way.

Barracks and React the Flux way

import barracks from 'barracks'// barracks uses a model (which contains reducers and effects, etc)
import model from './model'
// instantiate our store
const store = barracks()
// use our model
store.model(model);
// Use barracks state change hook to update our components
export function subscribe (component) {
store.use({
onStateChange: (state) => {
component.setState(state)
}
})
component.state = store.state() || {}
}

export const state = store.state
export default store

Now you can hook up your component to barracks using the subscribe function above like so:

import { subscribe } from '../store';class MyComponent extends Component {
constructor (props) {
super(props)
subscribe(this)
}
}

The component will now update its state every-time the reducers update it.

With barracks it is a bit easier to dispatch actions, because you dont need to mapDispatchToProps — instead you can simply call dispatch

import store from './store'
import { ActionTypes } from './constants'

const createSend = store.start({ subscriptions: true })
export const dispatch = createSend('todoApp', true)

const { ADD_TODO, REMOVE_TODO, TOGGLE_TODO, TOGGLE_ALL,
TOGGLE_EDIT, CLEAR_COMPLETED, SET_VISIBILITY_FILTER, SAVE_TODO } = ActionTypes

let nextTodoId = 0

export const addTodo = (text) =>
dispatch(ADD_TODO, {
id: nextTodoId++,
text
})

From there you can simply call addTodo and to update your state, like so:

import React, { Component } from 'react';
import { subscribe } from '../store';
import { addTodo } from '../actions';

const onSubmit = (e, input) => {
e.preventDefault()
if (!input.value.trim()) {
return
}
addTodo(input.value)
input.value = ''
}
class AddTodo extends Component {
constructor (props) {
super(props)
subscribe(this)
}
render() {
let input
return (
<header className="header">
<h1>todos</h1>
<form onSubmit={e => onSubmit(e, input)}>
<input ref={node => { input = node }} className="new-todo" placeholder="What needs to be done?" autoFocus />
</form>
</header>
);
}
}

export default AddTodo

You can see the full implementation here:

This post is a bit of a WIP, if you have questions or think some things need clearing up please leave a comment.

You can view the demo app here: http://barrax.surge.sh/

--

--

Matt McFarland

Software Engineer at Kroger with expertise in Javascript. Passionate about open source, learning new things, and making the development process easier.