Time for a somewhat embarrassing truth: I love the simplicity of redux on a theoretical level, yet somehow production setups of redux often confuse the hell out of me.

I think the main point which throws me off and makes it hard for me personally to work with redux production code is the huge amount of overhead that is usually required to build and maintain a working redux system.

Take the official React Redux TodoMVC example: The simple act of adding a todo to the store through a component involves 6 separate files:

ADD_TODO Action constant in constants/ActionTypes.js addTodo() Action creator function in actions/index.js Reducer in reducers/todos.js Root reducer in reducers/index.js Container Component in containers/App.js Actual visual component allowing users to add a todo in components/Header.js

(Take a look at this gist I created highlighting the code used from the files)

What’s so frustrating to me about this is that all I want to accomplish are two very simple tasks:

#1 Have my visual component call a function with some data that adds the todo item to the store

#2 Give that whole process a name — more specifically: Have a ADD_TODO action appear in my redux-devtools so I know what’s going on

Design goals of slim-redux-react

So to get around these issues, I create slim-redux & slim-redux-react with three specific design goals and redux’s basic principles in mind:

Design goal #1: Less boilerplate

While reading through the three core principles behind redux, I realized that it is possible to re-package how we work with redux, without compromising its original design goals.

slim-redux reduces boilerplate by letting you bundle action and reducer definitions into change triggers (that have optional payload validation).

slim-redux-react gives your react components quick access to the store through subscriptions and and lets them modify the state through change triggers.

Design goal #2: Faster to code

Especially for small state changes the regular redux-react approach takes a long time. I found myself having to setup quite a bit of code to what came down to changing a property in the state or adding an element to an array.

slim-redux and slim-redux-react were built in a way that makes defining store interactions and passing them to react components very fast and slim.

Design goal #3: Easier to reason about code

By bundling actions and reducers into change triggers (that have optional payload validation), everything you need to know about a specific store interaction lives in one file, inside a single API call.

When connecting slim-redux to your react components, a single API call lets you provide change triggers and store-subscriptions to your visual components which has a low enough footprint to export your visual- and your container component from the same file (most of the time)

Demo

A demo says more than a thousand words, so let’s take a look at a counter app built with slim-redux-react:

This code is the condensed version of the slim-redux-react counter example. You can just download it, npm install it and then npm start it :)

(you can also open up the gist in a new tab, to follow along)

Step #1: Create the slim-redux store

As with your regular redux code, we first of all need to create a store. Slim-redux is a good sport and happily co-exists next to your already existing redux code — you can pass in your existing root reducer and any middleware you already have to createSlimReduxStore() .

More details on how to include slim-redux-react into your existing redux apps in this recipe and in the API reference for createSlimReduxStore() .

Step #2: Create our counter component (just the presentational part)

Nothing fancy in this step — all we’re doing here is to create the counter component. Take a moment to look through the props that the counter component consumes:

props.counter which is the our counter state

which is the our counter state props.increaseCounter which is a callback to increase the counter

which is a callback to increase the counter props.decreaseCounter which is a callback to decrease the counter

Step #3: Create the change trigger definitions

This is where you encounter the first fundamental concept behind slim-redux-react: Actions and reducer definitions are bundled together into change triggers.

Change triggers bundle your action + reducer definitions. Everything you need to know about a specific store interaction in one place.

The beauty of change triggers is that you have everything you need to know about a specific store interaction in one place:

Action type, the reducer code and optional action payload validation at a glance.

Also can you imagine how fast you can add new actions + reducers like that? No more navigating through a thousand files — just add an object to your change trigger definitions and import it wherever you need it.

Step #4: Create the container component for the counter

In this step we connect our slim-redux store to our Counter component.

Notice how small the interface is!

Subcriptions: Map part of the state tree 🢂 props

Subscriptions are a simple mapping between part of the state tree and a prop. In this case we map the entire state to the props.counter .

In a more complex state tree you can map a path in the state tree to the prop you want to pass to your component — for example:

subscriptions: { completeTodos: 'state.todos.completed'}

Subscriptions are implemented using the reselect library for optimal performance.

Change triggers are also very straight-forward but let me explain quickly what happens in the background:

When calling createSlimReduxStore() slim-redux creates a standard redux store, but injects the slim-redux functionality into it. On initializing the store slim-redux also injects the store.createChangeTrigger() function into the store (more on that in the API reference).

When working only in slim-redux, here’s how you would register and use a change trigger:

When passing in change trigger definitions to slim-redux-react’s slimReduxReact() function, store.createChangeTrigger() will be called in the background and the resulting change trigger functions are passed along to your component.

So in our case, the Counter component gets props.increaseCounter() and props.decreaseCounter() as the functions it can call to modify the (counter) state.

Additional resources

I realize this post might have been quite the flood of new information so far, so let me close off this introduction by providing you with the resources to learn more about slim-redux & slim-redux-react:

Recipes:

🢂 slim-redux-react repository on github (npm package)

Recipes:

Closing words

The last two weeks of my life were exclusively dedicated to this project, so I really hope this is helpful to you. If you like these two projects, please be my new favorite human and give them a star on Github! :)

Also Dan Abramov, if you’re reading this: I didn’t steal your name “slim-redux”, I promise — I just saw now, after having finished this blog post, that you posted a pretty extensive gist by that name the other day. Sry about that! :)

Also I’d love to hear your thoughts, answer your questions and hear about suggestions for future development. So please don’t hesitate to get in touch on twitter.

And lastely a shameless plug: I’m currently looking for a full-time position as a react developer preferrably in Berlin. Know someone who might be interesting in hiring me? Please get in touch: jonas.peeck@googlemail.com

Thanks! :)