Let’s talk about state management in React. Or to be precise, why you might use MobX instead of Redux.
Recently we worked on the React Native app for Prepd and needed a state management solution. Easy task, isn’t it? That’s what we thought as well, so our default approach was to use Redux. Was there a particular reason to choose Redux? Not really, we just knew it was “the best solution” out there.
Redux is not for the faint-hearted
To be honest, we didn’t really ask ourselves how complex our project would be, how much state we’d need to manage, or what amount of data we’d have to deal with.
When I was mentally going through the process of building the whole thing with Redux, I began to feel a bit overwhelmed and had a lot of questions:
- How much data are we loading via the API? Does each of the calls have its own Redux action?
- Do we have to wait for all API calls to complete before showing any data?
- How do we handle navigation with Redux? Is this part of the state as well, needing to be reflected in the reducers?
- Do we implement jumping back and forth between screens ourselves, or does that happen automatically with Redux?
- How many reducers do we need for the content? Should each nested data object have its own reducer?
As you can see, I already had a lot of doubts about using Redux because I wasn’t experienced enough to come up with the right solutions. From the few things I had learned about Redux, I knew that even setting up the basic infrastructure can get incredibly complex.
Later in the development process, it emerged that fetching live API data was irrelevant: that became part of our app build process for the initial app release. The navigation challenges were resolved when we used a solid plugin. And jumping back and forth between screens was taken care of by ExNavigation’s internal mechanism, so there was no need to worry about that either.
Thinking about these questions and how to structure our app was really just a chimera. I think this is true for many people who approach state management for the first time: we immediately aim for the most sophisticated solution out there, even if it’s not the right tool for the job.
How we ended up using MobX
Luckily, we discussed this problem in the initial phase of the project, and one team member advocated for using MobX instead of Redux. I didn’t know a lot about it at that time, but it was said to be more automatic and less complex.
That began to sound like a much more appealing decision: by this point of the project the state management challenges had become much more manageable. We were very reluctant to risk getting sucked into a lot of structural optimisation before we could even build our first screen.
It also turned out that features like a central store and explicit state weren’t so critical after all, so we could build on a more automated solution instead. Given our time constraints, MobX was the ideal starting point as it didn’t dictate how to model our data, and it didn’t require us to structure our application around it either.
How we solved state management in our app
Since MobX doesn’t involve stores, actions and dispatchers, we just started out implementing our user interface and incorporated new MobX observables into our app logic as we needed them:
- We started out by using a simple array of objects (in our case: ‘lunchboxes’) that mocked the content later provided by the API
- Later, this array was replaced by a reference to a lunchbox object store which was responsible for initialising this store array and filling it up with lunchbox objects. This store is an @observable, and components could consume it as a data source.
- We had three different types of lists (unfiltered, filtered and favourites), each of them derived from the original lunchbox list, so using a @computed value made sense here, since it would allow us to return the original lunchbox array, pulled through a custom filter
- Later, we split up the store objects into more specific stores, each of them responsible for a separate chunk of content. That’s how we ended up building an OOP-style chain of objects: lunchboxes contains recipes contains ingredients
The app components were structured in a similar way, where the top component (the LunchboxList) would contain the app logic and the lunchbox array. Every time this changed, the changes would trickle down the component hierarchy to the presentational components that were just displaying the content.
If something had to change inside a component when the state updates, wrapping an @observer around its class guaranteed that it would respond to all state changes that happen to the @observable variables it is consuming.
For example, if the user changes her lunchbox preferences, the ListView displaying the list of lunchboxes would automatically update. That’s because Mobx listens to changes on the preferences value (which is an @observable), and the filtered lunchboxes array (which is a @computed value) depends on that observable. So it automatically updates the application state, and all the @observer components accessing those values. Pretty smart, right?
Some things I loved with MobX, but which others might not love so much
For us, MobX worked like a charm. I immediately fell in love with the concept of observable values (when one thing updates, everything that depends on it gets updated as well), which remove the need to dispatch an action, build complex reducers, and have a growing repository of actions that your app can dispatch.
As pointed out by others in the React community, MobX is based on an object-oriented view of the world: you have components inheriting information from other components, and a heavy use of the observer pattern.
With the rise of reactive functional programming, this paradigm naturally attracts a lot of resentment from more progressive app developers that prefer using cutting edge concepts and technologies such as Redux. And I don’t have anything against that, but with this post I wanted to make a little case for MobX, because it really helped us speed up our development process on this project and I think it’s a good fit if you don’t have to manage an extremely complex application state.
By the way: for a quick introduction to MobX, head over to egghead.io for a course by its very own creator, Michael Weststrate.