Kea vs setState, Redux, Mobx, Dva, JumpState, Apollo, etc.

Kea is the name of the latest state management library for React that you have never heard of.

It’s also the name of the smartest parrot in the world.

Much like kea the parrot, kea the library doesn’t invent anything new. Instead it manipulates existing tools to get results in the shortest time possible.

Kea the library is an abstraction over Redux, Redux-Saga and Reselect. It provides a framework for your app’s actions, reducers, selectors and sagas.

It empowers Redux, making it as simple to use as setState. It reduces boilerplate and redundancy, while retaining composability and making your code easier to read. It works especially well with React.

Because it’s just Redux, it’s immediately compatible with a large array of tools and libraries.

Enough talk, let’s see some code!

Kea vs setState

So how well does the claim “It empowers Redux, making it as simple to use as setState” hold up?

Before Kea 0.19, which introduced this feature, I repeatedly went through this process when writing a new page: I’d first write the JSX+CSS to get the page to look right. While doing so, I’d add a few setState calls here and there to open panes, fill input elements or do any other interactivity that was needed.

Later, after the state object had already grown to multiple keys, I would realise that I need access to this data from some other component or from the code that handles side effects.

Have you ever been there?

At this point I’d curse my decision to go for the simple solution in the beginning and rewrite the code to use Redux’s action creators and reducers. This way all my data would be in Redux and I could use selectors to access it wherever I needed.

It was too much work in the beginning, yet at some point it became unavoidable. I dreaded that point.

Now that’s a thing of the past. I haven’t written a setState call since Kea v0.19.

How come?

Let’s look at Kea vs setState for the simplest possible situation: a counter that we can increment and decrement with the push of a button!

Built with React’s setState, the code would look something like this:

While this code is definitely good enough for an example as simple as this, the issues outlined above still remain:

  • What if a component or saga outside <Counter /> needs access to the variable “counter”? It’s not uncommon to build the simplest solution with setState, only to have to rewrite it for Redux when the scope changes.
  • What if your UX changes and you need to show the counter in one component and the buttons in another? Move the state up?
  • setState can be called from anywhere in your component. How can you have an overview when does “counter” change? Could there be a rouge inlined this.setState({ counter: “banana” }) somewhere in render()?

Let’s rewrite the same code to use Kea instead:

The same number of lines and the same functionality, yet it’s fundamentally different:

  • Your code is clearly separated into actions and reducers, so you have a clear idea where data mutations happen. (Read Redux’s Three Principles if these concepts are unfamiliar to you). This means less bugs and happier developers!
  • Your data is stored in Redux. It takes 2 lines of code to change this example to one where other components can directly access “counter”, “increment” and “decrement”.
  • Because of the nature of Kea, if the logic above grows too big, you can rip it out of your index.js and place it in a separate logic.js with no changes between the brackets of kea({ … }). It would just work.
  • We haven’t even gotten to selectors or sagas yet.

Win-win-win!

Kea vs vanilla Redux

It’s hard to compare Kea and Redux, because Kea is Redux:

  • Kea stores its state in Redux’s store
  • To change the state you must emit an action
  • Reducers “listen to” actions and change the state accordingly

However Kea adds a lot of cream on top of vanilla Redux:

  • Your actions are automatically bound, so there’s no need to call dispatch, although it is available if you need it, e.g. for foreign actions.
  • Your action creators are your action types. Using some nifty toString() magic, inspired by redux-act, you can use the functions themselves directly as input keys to the reducer.
  • There is no need to create and duplicate type constants between files, nor is there a need to have 4+ different files. This is where most of Redux’s boilerplate comes from.
  • Using structure inspired by ducks, there is a clear and concise way to define actions and reducers.
  • Support for selectors is built in. All reducers automatically create selectors that you can use.
  • Sagas are a first class citizen, so you can handle side effects with ease.
  • Import, connect and use props and actions from other logic stores without trouble. You can seamlessly connect actions and reducers defined in one file with a component in another.

Let’s look at a bigger example that combines all of the above.

We will create a component that lets the user enter a username and then asks Github for all the repositories of that user.

The result will look like this:

And here’s the code:

It’s highly likely that without any explanation, you were able to read and grasp this code. However for a full breakdown, read the Github chapter in the Kea guide.

Let’s assume your application grows and you want to access reducers defined in one logic file from multiple components. How would you do that?

Like this:

Using these building blocks, I’ve been able to build very complex applications with ease. The final results have always been very refactorable (I could move code around with minimal effort) and very maintainable (newcomers to the project know immediately what is happening and where things come from).

There are many more aspects of Kea I could get into, but to keep this post from exploding in size, I’ll just direct you to the documentation if you’re curious to learn more.

Kea vs MobX

One of the selling points of MobX has always been that it’s really easy to get started with, compared to Redux.

For a lot of JavaScript developers, the biggest complaint with Redux is the amount of boilerplate code needed to implement features. A better alternative is MobX which provides similar functionality but with lesser code to write. — Sitepoint

As we saw above, using Kea that’s no longer the case with Redux: it’s very easy to get started and there’s virtually no boilerplate. That said, the simple example from above would still have fewer lines in MobX.

With that out of the way, let’s look at the bigger picture.

The thing that always bothered me with MobX is that it seems to take a step back in the evolution of software programming. It’s like writing EmberJS when everyone has switched to React.

I mean that literally. MobX reminds me of Ember-Data.

Probably the biggest legacy of React and Redux is making functional programming cool and mainstream on the frontend.

Who would have thought that by reducing the amount of operations you’re allowed to perform and strictly limiting the flow of data, your code becomes clearer, weird errors cease to exist and you get more done in the end?

Quoting Sir BenjiSponge on Reddit:

“MobX with React is taking a FP inspired library (React) and throwing a two-way [edit: not two-way!], mutable data store on top.”

It feels like a bad idea. Scattering your code with @observer, @computed, @observable and @action annotations, relying on magic and watching out for all the weird edge cases seems like going backwards to me.

Sure you can force yourself to use MobX like Redux, much like you can force yourself to write EmberJS like React. But a library’s legacy is not defined by what seasoned veterans of clean code can write. It’s defined by what the junior developers on your team who have no experience will write.

MobX is an impressive feat of engineering, no doubt!

Yet I believe that the single most important technical topic in programming is managing complexity. As humans we can only store about 7 ± 2 concepts in our short term memory. Every platform quirk you need to account for reduces the slots available to reason about your application. This means more bugs.

I could be proven wrong, but with Redux, Kea and other state libraries that operate according to functional programming paradigms, your code is simple on every level. With MobX you need to go a few levels deeper to grasp the full picture.

Kea vs Dva, JumpState, etc.

Two other libraries for managing state are Dva and JumpState. They operate similarly to Kea:

  • They provide a layer on top of Redux
  • They help you structure your actions, reducers and side effects

The main differences between them and Kea are, as far as I can see:

  • They introduce new concepts that are not present in redux, redux-saga and reselect, such as effects, hooks and subscriptions.
  • It’s harder to get started. You can’t just add something like @kea({}) and be done with it.
  • Actions seem to be tied to just one reducer, versus in Kea actions are shared among all the reducers in a logic store and even with external logic stores.
  • It’s not as easy to share actions and props between components as it is with Kea’s connect

There are a few small benefits in dva, such as the ability to easily subscribe to any action, such as a key press or an incoming websocket connection, but those are not hard to bootstrap on your own.

I found a few other React state libraries out there, but none which seemed as widely used or still maintained as the ones mentioned above. If I missed anything important, let me know!

Kea vs React-Apollo

Finally, there’s React-Apollo, Relay and other GraphQL-based libraries.

Kea doesn’t intend to compete with them. In fact, you can use Kea and Apollo together seamlessly. Use Apollo to fetch your data and Kea to manage all the other interactivity your application needs. Win-win!

In conclusion

If you haven’t already, please give Kea a try. Tell your friends about it, share this post, give a star on Github and keep being awesome!

You should also follow me on twitter at @mariusandra.

Thanks for reading! :)

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.