TLDR: I created new state library called Exome (works with React and there's a PR for Vue too (excuse me, that sounded like a pokemon)). The end.
Introduction
Let me introduce myself first. I'm working as a front-end dev for as long as I can remember. Since before the days of jQuery dominance even. So I've seen a lot from dead simple JS libraries to utterly complex ones and again back to simple ones and so on. When I started learning Redux, NgRx and Vuex back in a day it was a high hill to climb at first always wishing for something easier. Much easier, like a plain object being state easier.
So I started tinkering with different ideas of how I would like my ideal state manager to look and feel years ago. I remember having random ideas at random times and just dropped them in notes. I never did anything with those because none of them really felt good enough.
Until now when I reached a point when starting new project where working with deeply nested tree structures was a must have. Since that is one of Redux (and I'd say the whole flux architecture for that matter) core problems, I went with valtio, a library by Pmndrs. And it was great at first, but then I started to see a real mess in code with my made up actions and selectors making sense less and less. And line between what gets selected from state and what updated became blurred together. So I knew that I had only one option, to finally figure out my dream state manager.
From idea to library
I set a few goals for state manager I wanted:
- Must have actions (in a sense that it would be the only way to modify state);
- Must integrate with Redux Devtools and to see deeply nested objects right away, not clicking through tree to find exact one I'm looking for;
- Must be typed via TypeScript, I mean when working with data, there must be some guards and of course that sweet autocomplete;
- Must be able to save and load as a string (since in my case I needed a way to save state in a file and restore it);
- Must be dead simple so any junior developer can get productive right away;
- Must not bottleneck the view renderer (must be performant).
So those were my initial goals and in a single evening I came up with Exome and developed a prototype. I was so happy with it that I decided to make it open source. It really hits all of the goals I set and more. Only issue is that it doesn't support IE11, since it uses Proxy. But in my case it didn't matter. Not true anymore! It support IE11 too.
Examples
So to start off here's a primitive counter example (click on number to increment it).
And that's it, no providers, no contexts, no boilerplate. Store is just a class. Properties are state values and methods are actions. Whenever action is called, state is updated and wired view components (via useStore
) are rendered. It updates only those components that uses particular Exome instance in useStore
hook. It's simple as that.
Ok everyone can do a counter example. What about that deeply nested tree part that was in my goals. Aah great question. So I threw up a simple router example for this.
This is more complex one. I wanted to demonstrate here that we can have Store that can have multiple Tabs and those Tabs can also have multiple Items. So it's a nested tree. Just pass child Exome instance through useStore
and that child component will be wired.
Devtools
Working with Redux Devtools to examine Exome state is a breeze too. No need to dig deep into state tree to find Exome you're looking for. But if you want to see whole tree, that's available too (all Exome childs are examinable in full tree view).
Note: Since devtools have weird bugs when using serializedType
every Exome will have $$exome_id
until those bugs are resolved.
Saving and loading state is described in details in API docs (https://github.com/Marcisbee/exome#savestate).
Performance
It's great! And will be more and more optimised as library matures.
To get the feel of how this library performs, I created a benchmarks (really, really primitive ones). And the results are quite good, in fact Exome seems to be the fastest library out of what I've tested (at least on my machine — Macbook Pro 2020 M1). And here are the results:
It's a simple counter example in React, that gets rendered in first benchmark. And in second one count gets incremented and rendered via view update.
Please note that these benchmarks are not intended to make any library look bad (in fact they all are really great). Main intention is to see where Exome stands in terms of Performance and where and how to improve it. And I know those are very primitive benchmarks, but I don't really want to spend a lot of my time to create real world apps for each store. Maybe in future.
Conclusion
There are more perks to Exome that we didn't explore, but most of them are explained in readme.
The most exciting one is that micro-frontends can share single state between them. I created a tiny example where I created single Exome store and passed it to React and Vue. Whenever something changes in state, it gets synced across all frameworks that utilise Exome middleware. It just works.
I'm really excited for what future brings. For now I'm gonna go dogfeed and battle test this library. See ya later.
Top comments (16)
Dude this is really nice, you might have just created the next great state library😄
Thanks! 😄 I hope people find it useful.
This is... unorthodox and wonderful.
Thanks!
it looks amazing 😵🤔
I’ll use it on the next project, let’s see if it’s easy as it sounds 💪🏻
I'm happy to announce that Exome now supports IE11 too 🥳
github.com/Marcisbee/exome#ie-support
Thanks! Let me know in github discussions what could be improved 👍🏼
What about IE11 bug?
Do you any idea to bypass the problem?
I'm using
Proxy
here that is not supported in IE11.But I am keen on making it work on IE11 since I know in many companies whose clients use IE11 heavily. Will be investigating this in near future.
Got curious and checked.
Actually IE11 support will be very easy add since I'm using very small part of Proxy Object and that part is supported via Proxy Polyfill.
Can confirm, is very easy and nice to use! I was a little worried about async/promise stuff, but basically just kick off a promise from some event and then call the methods and it all works 👍👍
Thanks for giving it a try!
Just realised I should probably add some examples with promises in readme, totally forgot.
Did you try to share states between React and React Native? Is this something you want to support any time soon?
I haven't tried it with React Native yet. It's in my todo list.
What would be the use case of sharing state between React Native and React?
A game between two person but I guess we are stuck with a client server architecture in the end for now. Or maybe have some sort of helper that can be used in the server to not have to deal with all that. That would be awesome.
Yes, this probably have to be a server talking to clients. But Exome probably could have some sort of helper you mentioned. Will write this down as a feature to have in future.