When starting our last project, we had long discussions about immutability of our state. Using spread operator or Object.assign in reducers didn’t quite cover our requirements. As crazy as we sometimes are, we decided for various reasons not to use ImmutableJS like most people do - instead, we went with mori. Combining reducers with redux’s combineReducers wouldn’t work in our case as it only works with plain JS objects. We looked around for a solution that we could use instead, something similar to redux-immutable. After a while, it became obvious that if we really want to use mori in our redux app, we’d need to write our own solution - and that’s how redux-mori was born.
Tl;dr: Redux-mori is a very slim library that allows using mori’s immutable data structures for state (and action) objects in a redux app.
It's a little bit less nonsensical than this - promise.
I mean do we even have to explain this?
I think it’s fair to stop for a while before getting on with our project to explain why and how we use mori - and what it actually is.
A few examples would probably make it clearer than a whole article on the topic. Let’s see how it actually looks when used in our apps?
1. When we get data from our server, we convert it immediately to a hashMap.
2. We then pass this data into our reducer using an appropriate action.
3. Finally, to use our state in components, we change clojure data into plain JS data at the last possible moment.
In the examples above, we’ve pretty much exhausted all mori functions and structures we use in our app. Mori has much more to offer though, and I’d really encourage you to have a good look at their docs to learn more cool stuff.
We decided to go for mori for a lot of more or less “emotional” reasons. First of all, we’re quite into functional programming and Clojure here at Red Badger. We like immutability and pure functions and aren’t that keen on objects.
Another reason we wanted to dodge ImmutableJS is the API. After using it on a few previous projects, some coders on our team were quite tired of the object-oriented, slightly over-complicated way of accessing and creating data structures.
Last but not least - with every project, we strive to learn more, to explore various options, and have fun. When we spotted something few people have done before, we wanted to get out there and try it out.
You could have noticed that so far, we haven’t really used redux-mori in our examples. We really don’t need it for that much at the end of the day; we just need to re-write a few redux functions to work with a different data structure.
1. In your root reducer:
2. To create your store:
This way both your state and actions will be clojure data. When logged into the console using redux-logger, they will be automatically translated back into plain JS objects so it’s easily readable when debugging.
Why we like it
Doing things this way seems to be working out for us pretty well. Here’s list of pros:
- It’s immutable
- It’s functional
- It’s readable
- It’s reliable
- It makes sense as a part of our workflow
Using it with other redux “extensions” such as redux-saga and redux-form can be tricky (same worked for redux-logger until we wrote our wrapper). These libraries typically expect you to have state as plain JS object and often doesn’t allow you to modify data structure of your app at all.
In order to make it work with redux-saga, we decided not to use createStore from ‘redux-mori’ in our current project. It works fine with redux-thunk however and we’re planning to extend either our project or submit a PR to redux-saga so that we can “go mori” all the way.
When trying to find a work-around for redux-form, Erik Rasmussen pointed out that redux-form support ImmutableJS already but not other data formats. There’s a “hack” of sorts that you can use though so even this problem has a solution.
Even if you’re not as adventurous (or mad) as we are and you want to stick to solutions well proven by others, I’d encourage you to give this a try. If you have any problems with making it work, feel free to get in touch on twitter.
We welcome any comments, issues, discussions, and pull requests.
And to conclude with - have fun, writing in a functional way is sexy ;)